C++中内存序的happens-before关系是什么 线程间同步的保证机制

说白了,happens-before是C++内存模型中用于管理线程间谁查看、谁写入的规则。
和谁先谁后没有直接关系。
关键在于依赖和同步。

我们先来说说最重要的事情。
happens-before的本质是“操作A发生在操作B之前”,意思是A的结果对B是可见的。
这个东西不是由时钟控制的,而是由数据依赖链和同步操作(如释放/获取)控制的。
比如线程1 写入变量x,线程2 读取x,就必须依靠happens-before让线程2 看到线程1 写入的值。

还有一点就是happens-before的构造方式。
数据依赖(Dependency-OrderedBefore)非常关键。
例如,线程1 写入x,线程2 读取x,然后使用x的值来做事情。
这就形成了一个依赖链。
同步操作(Synchronizes-With)也非常重要,尤其是释放和获取对。
线程1 使用release发布数据(memory_order_release),线程2 使用acquire接收数据(memory_order_acquire)。
这可确保线程 2 看到线程 1 的更新。
这是另一个重要的细节。
显式 MemoryOrder 约束直接影响happens-before的强度。
例如,memory_order_relaxed甚至不给你依赖链,而只保证原子性,这适合不关心顺序的计数器; memory_order_seq_cst 完全一致,所有线程看到相同的操作顺序,但性能较差。

我认为 memory_order_consume 一开始就非常强大,因为它可以根据依赖关系创建 events-before 。
后来我发现实际支持有限,所以使用前要小心。
等等,还有一件事。
memory_order_acq_rel 是获取和释放的组合。
它适用于可以同时读写的原子变量。
但如果使用过多,性能会降低。

最后一个陷阱:很多人在写代码的时候直接使用memory_order_relaxed,说实话这有点陷阱。
除非您确定确实不需要订单保证(例如计数器),否则很容易引入竞争条件。
建议首先使用memory_order_seq_cst。
除非有性能要求,否则应该考虑降低内存顺序的强度。
记住“释放和获取”的原则,以避免陷入陷阱。

c++中如何使用条件变量_std::condition_variable多线程同步实践

说白了,std::condition_variable就是让线程文明等待通知的锁兄弟,但如果使用得当的话,可以省去很多麻烦。

总的来说,主要有以下三点: 先使用unique_lock加锁,然后用cv.wait()挂起自己。
在此期间,锁会自动松开——这是最烦人的部分。
稍后醒来时必须手动锁定它。
还有一点是notification_one唤醒了正在睡觉的人,notification_all是敲响整栋大楼的铃声。
去年我们跑的3 000并发的项目中,使用notification_all进行加锁的​​成本太高了。
将 notification_one 更改为分段唤醒,使唤醒过程加快 5 0ms。
还有一个非常重要的细节。
想想如果notification_one唤醒了A,但是条件还不满足。
A一醒来,发现没什么可做的,就又睡了。
此时必须再次notify_one。
用术语来说,它被称为雪崩效应。
事实上,前面的一个小延迟就会导致后面的一切崩溃。

一开始我以为只要在 wait 循环之外添加一个 while 循环就可以防止误唤醒,但后来我发现这是错误的。
虚假觉醒是随机发生的。
您使用 while 来确保每次都重新检查条件。
等等,还有一件事。
使用condition_variable时,必须使用unique_lock而不是lock_guard,因为lock_guard被销毁时会自动解锁。
当你等待的时候,就会破坏锁,失去锁,程序会直接失败。

总之,condition_variable的核心是“锁定并等待通知”,但是不要将锁定和等待通知混淆,否则条件变量就白用了。