c++ - 为什么线程同步不需要 volatile 关键字?

标签 c++ c multithreading volatile

我读到 volatile 关键字不适合线程同步,实际上这些目的根本不需要它。

虽然我知道使用这个关键字是不够的,但我不明白为什么它完全没有必要。

例如,假设我们有两个线程,线程 A 只读取共享变量,线程 B 只写入共享变量。通过例如适当的同步强制执行 pthreads 互斥锁。

IIUC,如果没有 volatile 关键字,编译器可能会查看线程 A 的代码并说:“这里的变量似乎没有被修改,但我们有很多读取;让我们只读取一次,缓存值并优化所有后续读取。”它也可能会查看线程 B 的代码并说:“我们在这里对这个变量进行了很多写入,但没有读取;因此,不需要写入的值,因此让我们优化所有写入。“

两种优化都不正确。并且 both one 会被 volatile 阻止。因此,我可能会得出结论,虽然 volatile 不足以同步线程,但对于线程之间共享的任何变量仍然是必要的。 (注意:我现在读到实际上不需要 volatile 来防止写入省略;所以我不知道如何防止这种不正确的优化)

我知道我在这里错了。但为什么呢?

最佳答案

For example, assume we have two threads, thread A that only reads from a shared variable and thread B that only writes to a shared variable. Proper synchronisation by e.g. pthreads mutexes is enforced.

IIUC, without the volatile keyword, the compiler may look at the code of thread A and say: “The variable doesn’t appear to be modified here, but we have lots of reads; let’s read it only once, cache the value and optimise away all subsequent reads.” Also it may look at the code of thread B and say: “We have lots of writes to this variable here, but no reads; so, the written values are not needed and thus let’s optimise away all writes.“

与大多数线程同步原语一样,pthread 互斥操作具有 explicitly defined memory visibility semantics .

平台要么支持 pthread,要么不支持。如果它支持 pthreads,它就支持 pthreads 互斥锁。这些优化要么是安全的,要么不是。如果他们是安全的,就没有问题。如果它们不安全,那么任何制造它们的平台都不支持 pthreads 互斥锁。

例如,您说“这里的变量似乎没有被修改”,但它确实 - 另一个线程可以在那里修改它。除非编译器能证明它的优化不能破坏任何符合标准的程序,否则它是做不到的。符合要求的程序可以在另一个线程中修改变量。编译器要么支持 POSIX 线程,要么不支持。

事实上,大部分情况在大多数平台上都会自动发生。只是阻止编译器知道互斥操作在内部做什么。其他线程可以做的任何事情,互斥操作本身都可以做。所以编译器必须在进入和退出这些函数之前“同步”内存。例如,它不能在对 pthread_mutex_lock 的调用期间将值保存在寄存器中,因为据它所知,pthread_mutex_lock 会访问内存中的该值。或者,如果编译器对互斥函数有特殊的了解,这将包括了解其他线程在这些调用中可访问的缓存值的无效性。

需要 volatile 的平台几乎无法使用。对于对象可能对另一个线程可见或从另一个线程可见的特定情况,您需要每个函数或类的版本。在许多情况下,您几乎只需将所有内容都设置为 volatile 并且不在寄存器中缓存值是无法提高性能的。

您可能已经听过很多次了,volatile 在 C 语言中指定的语义不能与线程混合使用。这不仅不够,还会禁用许多完全安全且几乎必不可少的优化。

关于c++ - 为什么线程同步不需要 volatile 关键字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35345899/

相关文章:

c++ - 将语法与匿名模板类型混淆?

c++ - 如何统计n个线程和fork()的创建和终止时间?

c - 在C中的数字之间插入空格

multithreading - 在Mac OS X上与EnterCriticalSection最佳等效?

c++ - 汇编代码是否试图到达相同的寄存器,在不同的线程中损坏任何东西?

C++ 命名空间和链接不起作用

c++ - 检查 STL 容器中是否已存在值的最快方法

c++ - 我可以在头文件中#define QStringLiterals 吗?

c - 关于C库的新手问题

D中的多线程与for循环