Java中持互斥量的共享变量无需volatile,C++中是否同理?
C++中互斥量与共享变量可见性的问题
在Java内存模型(JMM)中,线程A写入字段后解锁互斥量时,该写入操作“先行发生于”解锁操作。这意味着只要两个线程在同一同步块/互斥量下操作共享变量,无需将变量声明为volatile就能保证变更可见性——因为共享互斥量会创建内存屏障。那这个规则在C++中是否同样适用?
参考以下代码:
std::mutex m; int x = 0; std::cout << "Starting async:\n"; auto future1 = async(launch::async, [&] { for (int i = 0; i < 100000; ++i) { m.lock(); ++x; m.unlock(); } }); auto future2 = async(launch::async, [&] { for (int i = 0; i < 100000; ++i) { m.lock(); ++x; m.unlock(); } }); std::cout << "After calling async. Waiting for result from async:\n"; future1.get(); // wait for thread1 future2.get(); // wait for thread1 std::cout << "x = " << x;
问题答案:不需要将x声明为volatile
C++标准通过互斥量的lock()和unlock()操作定义了明确的**先行发生(happens-before)**关系:
- 一个线程对某互斥量的
unlock()操作,先行发生于后续其他线程对同一互斥量的lock()操作。 - 线程在获取锁(
lock()成功)后执行的所有操作,能够看到之前所有解锁该互斥量的线程对共享变量做出的修改。
在给出的代码中,两个工作线程都通过同一个std::mutex保护对x的修改:每次++x都被包裹在lock()和unlock()之间。线程1的unlock()会先行发生于线程2的lock(),因此线程2能看到线程1对x的最新修改;同理,主线程通过future.get()等待两个线程完成,这一操作也建立了先行发生关系,主线程最后读取x时,能确保看到两个线程的所有修改结果。
另外需要明确:C++中的volatile关键字不提供线程间的同步或可见性保证,它仅用于阻止编译器对变量读写做优化(比如避免将变量缓存到寄存器)。对于已经用互斥量正确保护的共享变量,添加volatile完全多余,甚至可能干扰编译器的正常优化。
内容的提问来源于stack exchange,提问作者Gonen I
相关产品推荐
相关产品推荐

