如果lock可以防止volatile的使用
If lock can prevent the use of volatile
如果不使用 volatile,我怎么知道变量是从内存中读取的而不是注册的。
static uint64 counter;
void thread(void *arg){
while(counter < (uint64)arg){
acquire(&lock)
counter++;
release(&lock);
}
}
之前我从来没有怀疑过,但是如果有编译器优化,它会不会产生
不好的结果。
我还发现 volatile 在 xv6 内核代码中很少见,我想知道是否有一些技巧可以
通过编译器的命令行抑制优化以防止使用 volatile。
您不需要 volatile
只要您的锁定库被正确实现 - 它会(通过设计)保证正确的行为,尽管编译器优化,线程争用相同的资源,调度其他处理器和内核等
A properly-implemented acquire
和 release
将保证编译器不会产生不需要的重新排序,更重要的是,它还将保证 处理器(及其关联的缓存控制器)不会产生不需要的重新排序(这可能发生在某些处理器架构上,即使编译器发出所需的操作序列)。
实现此目的的一种方法 是使用障碍。我将它更多地作为对事物如何工作的解释,并且 而不是 作为手写此类同步代码的建议:
acquire
函数包括一个具有“获取语义”的 so-called 内存屏障 - 获取屏障意味着后面的任何代码它(即关键部分内的代码)不得重新排序以在屏障之前发生。这意味着任何其他线程和处理器都必须在关键部分的任何写入之前看到锁的获取。
release
函数提供了一个类似的内存屏障,可以防止临界区中的任何内容在屏障之后被重新排序。这确保其他线程在看到锁被释放之前会看到临界区的效果。
除非您正在编写一个 low-level 库并准备彻底证明、验证和测试它,否则您不应该自己编写这种屏障代码。很容易犯细微的错误、性能低下等。
如果不使用 volatile,我怎么知道变量是从内存中读取的而不是注册的。
static uint64 counter;
void thread(void *arg){
while(counter < (uint64)arg){
acquire(&lock)
counter++;
release(&lock);
}
}
之前我从来没有怀疑过,但是如果有编译器优化,它会不会产生 不好的结果。 我还发现 volatile 在 xv6 内核代码中很少见,我想知道是否有一些技巧可以 通过编译器的命令行抑制优化以防止使用 volatile。
您不需要 volatile
只要您的锁定库被正确实现 - 它会(通过设计)保证正确的行为,尽管编译器优化,线程争用相同的资源,调度其他处理器和内核等
A properly-implemented acquire
和 release
将保证编译器不会产生不需要的重新排序,更重要的是,它还将保证 处理器(及其关联的缓存控制器)不会产生不需要的重新排序(这可能发生在某些处理器架构上,即使编译器发出所需的操作序列)。
实现此目的的一种方法 是使用障碍。我将它更多地作为对事物如何工作的解释,并且 而不是 作为手写此类同步代码的建议:
acquire
函数包括一个具有“获取语义”的 so-called 内存屏障 - 获取屏障意味着后面的任何代码它(即关键部分内的代码)不得重新排序以在屏障之前发生。这意味着任何其他线程和处理器都必须在关键部分的任何写入之前看到锁的获取。release
函数提供了一个类似的内存屏障,可以防止临界区中的任何内容在屏障之后被重新排序。这确保其他线程在看到锁被释放之前会看到临界区的效果。
除非您正在编写一个 low-level 库并准备彻底证明、验证和测试它,否则您不应该自己编写这种屏障代码。很容易犯细微的错误、性能低下等。