关于std::binary_semaphore的release()是否保证早于acquire()完成的疑问
疑问:std::binary_semaphore的release()是否保证早于配对的acquire()完成?
嘿,你的担心真的不是杞人忧天——多线程同步里的这些细节稍不注意就会出大问题,咱们结合你的代码来掰扯清楚这个事儿。
先把你的场景代码贴出来方便大家看:
class MyClass { std::binary_semaphore sem{0}; std::binary_semaphore& sem(); // 内部返回sem的引用 // 其他成员 }; void func1(MyClass& obj) { // 一些代码 obj.sem().release(); } void func2(MyClass& obj) { // 一些代码 obj.sem().acquire(); obj.~MyClass(); }
假设线程A在调用func1里的release(),线程B在调用func2里的acquire(),你怕的是会不会出现acquire()已经完成了,但release()还没彻底做完的情况?
放心,C++标准给std::binary_semaphore的操作做了明确的同步保证:
- 当一个线程的
release()操作使得信号量的计数从0变成1,另一个线程的acquire()因此成功返回时,release()的所有内存操作和副作用都在acquire()完成之前就已经结束了,而且标准定义了release()的完成是happens-beforeacquire()的完成的。简单说就是,只要acquire()成功拿到了信号量,那之前的release()肯定已经彻底做完了,不会有“半拉子”的情况。
不过这里还要提醒你一个代码里的小问题:func2里手动调用obj.~MyClass()是非常危险的操作,除非这个MyClass对象是用placement new在手动分配的内存上创建的。正常情况下,对象的析构应该由它的生命周期自动管理(比如栈对象出栈、智能指针自动释放),手动调用析构很容易导致重复析构、或者其他线程还在访问对象时就被析构的问题——哪怕这里的信号量同步没问题,手动析构本身就是个坑。
总结一下:你担心的release()和acquire()的顺序问题,标准已经给你兜底了,只要acquire()成功返回,release()肯定已经完成。但手动调用析构的操作一定要改,别给自己埋雷。
内容来源于stack exchange
相关产品推荐
相关产品推荐

