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