我有一个类,它有一个状态(一个简单的枚举),可以从两个线程访问。为了改变状态,我使用互斥锁(boost::mutex)。检查状态是否安全(例如比较 state_ == ESTABLISHED)还是在这种情况下我也必须使用互斥锁?换句话说,当我只想读取一个可以由另一个线程同时写入的变量时,我是否需要互斥锁?
6 回答
这取决于。
C++ 语言没有提到线程或原子性。
但是在大多数现代 CPU 上,读取整数是原子操作,这意味着即使没有互斥体,您也将始终读取一致的值。
但是,如果没有互斥体或其他形式的同步,编译器和 CPU 可以自由地重新排序读取和写入,因此任何更复杂的事情,任何涉及访问多个变量的事情,在一般情况下仍然是不安全的。
假设写线程更新了一些数据,然后设置一个整数标志来通知其他线程数据可用,这可以重新排序,以便在更新数据之前设置标志。除非您使用互斥锁或其他形式的内存屏障。
因此,如果您想要正确的行为,则不需要这样的互斥锁,并且如果另一个线程在您读取变量时写入变量也没问题。除非你在一个非常不寻常的 CPU 上工作,否则它将是原子的。但是您确实需要某种内存屏障来防止在编译器或 CPU 中重新排序。
你有两个线程,它们交换信息,是的,你需要一个互斥锁,你可能还需要一个条件等待。
在您的示例中(比较 state_ == ESTABLISHED)表示线程 #2 正在等待线程 #1 启动连接/状态。如果没有互斥锁或条件/事件,线程#2 必须不断地轮询状态。
线程用于提高性能(或提高响应能力),轮询通常会导致性能下降,要么消耗大量 CPU,要么由于轮询间隔引入延迟。
是的。如果线程 a 在线程 b 正在写入变量时读取变量,则可以读取未定义的值。读写操作不是原子的,尤其是在多处理器系统上。
一般来说,如果你的变量是用“volatile”声明的,你不会。并且仅当它是单个变量时 - 否则您应该非常小心可能的比赛。
应该保护对枚举的访问(读或写)。
另一件事:如果线程争用较少并且线程属于同一进程,那么关键部分将比互斥锁更好。