我需要一个互斥量来阅读吗?

39 c++ multithreading mutex

我有一个具有状态(一个简单的枚举)的类,可以从两个线程访问.为了改变状态,我使用互斥锁(boost :: mutex).检查状态是否安全(例如比较state_ == ESTABLISHED)还是在这种情况下我是否必须使用互斥锁?换句话说,当我只想读取一个可以由另一个线程同时写入的变量时,我是否需要互斥锁?

jal*_*alf 19

这取决于.

C++语言没有提及线程或原子性.

但是在大多数现代CPU中,读取整数是一个原子操作,这意味着即使没有互斥锁,也总是会读取一致的值.

但是,如果没有互斥锁或其他形式的同步,编译器和CPU可以自由地重新排序读取和写入,因此任何更复杂的,涉及访问多个变量的任何东西,在一般情况下仍然是不安全的.

假设编写器线程更新了一些数据,然后设置整数标志以通知其他线程数据可用,则可以重新排序,以便更新数据之前设置标志.除非您使用互斥锁或其他形式的内存屏障.

因此,如果您想要正确的行为,那么您不需要这样的互斥体,如果另一个线程在您读取变量时写入该变量,则没有问题.除非你在一个非常不寻常的CPU上工作,否则它将是原子的.但是你需要某种形式的记忆屏障,以防止重新排序在编译器或CPU.

  • 但即使使用volatile,CPU或编译器也可能会对写入进行重新排序,使它们变得毫无意义.正确的解决方案是内存屏障,然后volatile只是一种不必要的去优化. (4认同)
  • 但是,如果正在检查标志以确定其应用程序中的下一步,则(a)他需要在线程之间共享一些其他数据.(b)旗帜检查毫无意义,他可以随时执行下一步骤.假设(a)是场景,"其他数据"可能因为设置了标志变量而未准备就绪.假设这是因为标志是一个可能怀疑run-in-debug-crashes-in-release-build. (2认同)

Ern*_*lli 9

你有两个线程,他们交换信息,是的,你需要一个互斥,你可能还需要一个条件等待.

在您的示例中(比较state_ == ESTABLISHED)表示线程#2正在等待线程#1发起连接/状态.如果没有互斥锁或条件/事件,线程#2必须不断轮询状态.

线程用于提高性能(或提高响应性),轮询通常会导致性能下降,无论是消耗大量CPU还是由于轮询间隔引入了潜在性.


Jef*_*ber 2

是的。如果线程 a 在线程 b 写入变量时读取该变量,则可以读取未定义的值。读写操作不是原子的,尤其是在多处理器系统上。

  • 当编写器线程执行(获取->写入->存储)时,我看不到读者何时会获取未定义的值,无论是前一个还是后一个,但永远不会未定义。 (2认同)