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