Ziz*_*Tai 3 c++ multithreading reference-counting memory-model stdatomic
考虑以下简单的引用计数函数(与 一起使用boost::intrusive_ptr):
class Foo {\n // ...\n\n std::atomic<std::size_t> refCount_{0};\n\n friend void intrusive_ptr_add_ref(Foo* ptr)\n {\n ++ptr->refCount_; // \xe2\x9d\xb6\n }\n\n friend void intrusive_ptr_release(Foo* ptr)\n {\n if (--ptr->refCount_ == 0) { // \xe2\x9d\xb7\n delete ptr;\n }\n }\n};\nRun Code Online (Sandbox Code Playgroud)\n\n我仍在学习内存排序,我想知道在这种情况下fetch_add/sub( memory_order_seq_cst) 的默认内存排序是否太严格。由于我想确保的唯一顺序是在 \xe2\x9d\xb6 和 \xe2\x9d\xb7 之间,我认为我们可以将 \xe2\x9d\xb6 替换为
ptr->refCount_.fetch_add(1, std::memory_order_release);\nRun Code Online (Sandbox Code Playgroud)\n\n和 \xe2\x9d\xb7 与
\n\nif (ptr->refCount_.fetch_sub(1, std::memory_order_consume) == 1) {\nRun Code Online (Sandbox Code Playgroud)\n\n但内存排序对我来说仍然是新的和微妙的,所以我不确定这是否能正常工作。我错过了什么吗?
\n参考 的 libc++ 实现std::shared_ptr,您可能需要memory_order_relaxed增量和memory_order_acq_rel递减。合理化这种用法:
如果数量增加,那么最重要的是其一致性。当前线程已经确定它大于零。其他线程是不同步的,因此它们将在下一次原子修改之前的不确定时间看到更新,并且可能与其他变量的更新不一致。
如果数量减少,那么您需要确保当前线程已经完成对其的修改。来自其他线程的所有更新都必须可见。当前的减量必须对下一个减量可见。否则,如果计数器跑到它所守护的物体之前,则该物体可能会过早被摧毁。
Cppreference有一个关于内存排序的很好的页面。它包括以下注释:
释放-消费排序规范正在修订,暂时不鼓励使用
memory_order_consume。
它还暗示当前的编译器或 CPU 都没有实现consume;它实际上与 相同acquire。