如果不使用volatile,我怎么知道变量是从内存而不是寄存器中读取的.

static uint64 counter;

void thread(void *arg){
  while(counter < (uint64)arg){
    acquire(&lock)
    counter++;
    release(&lock);
  }
}

我以前从未怀疑过这一点,但如果有编译器优化,它不会产生

推荐答案

只要正确实现了锁定库,就不需要volatile—它(通过设计)将保证正确的行为,尽管编译器优化、线程在同一资源上竞争、在其他处理器和内核上调度等等.

正确实现的acquirerelease将保证编译器不会产生错误的重新排序,更重要的是,保证processor不会产生错误的重新排序(这可能发生在某些处理器体系 struct 上).

要做到这一点,需要使用屏障.我将其更多地作为对事物如何工作的解释,并将其作为手写此类同步代码的建议:

  • acquire函数包括一个带有"acquire semantics"的所谓memory barrier,acquire barrier意味着它后面的任何代码(即关键部分内的代码)都不能被重新排序为发生在barrier之前.这意味着任何其他线程和处理器都必须在从临界段进行任何写入之前看到锁的获取.

release函数提供了一个类似的内存屏障,可防止关键部分中的任何内容在屏障后重新排序.这可以确保其他线程在看到释放锁之前,会看到临界部分的效果.

除非您正在编写一个低级库,并准备彻底证明、验证和测试它,否则您不应该自己编写这种障碍代码.很容易犯细微的错误、性能低效等.

C++相关问答推荐

Apple Libm的罪恶功能

如何一次获取一个字符

变量>;-1如何在C中准确求值?

试图从CSV文件中获取双精度值,但在C++中始终为空

如何使用指向 struct 数组的指针并访问数组中特定索引处的 struct

在C++中访问双指针

X64:并发写入布尔数组

如何在C中只对字符串(包含数字、单词等)中的数字进行重复操作?

为什么Fread()函数会读取内容,然后光标会跳到随机位置?

为四维数组中的Dim-1和Dim-3重新分配空间

为什么Linux无法映射这个PT_LOAD ELF段?

*S=0;正在优化中.可能是GCC 13号虫?或者是一些不明确的行为?

有没有办法减少C语言中线程的堆大小?

使用mmap为N整数分配内存

%g浮点表示的最大字符串长度是多少?

struct 中的qsort,但排序后的 struct 很乱

程序打印一些随机空行

execve 不给出which命令的输出

Clang 是否为内联汇编生成了错误的代码?

假设函数调用返回的 string(char *) 上有 free() 是否安全?