我正在将一个在准系统上运行的项目迁移到 linux,并且需要消除一些{disable,enable}_scheduler
调用。:)
所以我需要一个单写多读场景中的无锁同步解决方案,写线程不能被阻塞。我想出了以下解决方案,它不适合通常的获取-发布顺序:
class RWSync {
std::atomic<int> version; // incremented after every modification
std::atomic_bool invalid; // true during write
public:
RWSync() : version(0), invalid(0) {}
template<typename F> void sync(F lambda) {
int currentVersion;
do {
do { // wait until the object is valid
currentVersion = version.load(std::memory_order_acquire);
} while (invalid.load(std::memory_order_acquire));
lambda();
std::atomic_thread_fence(std::memory_order_seq_cst);
// check if something changed
} while (version.load(std::memory_order_acquire) != currentVersion
|| invalid.load(std::memory_order_acquire));
}
void beginWrite() {
invalid.store(true, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
void endWrite() {
std::atomic_thread_fence(std::memory_order_seq_cst);
version.fetch_add(1, std::memory_order_release);
invalid.store(false, std::memory_order_release);
}
}
我希望意图很明确:我将(非原子)有效负载的修改包装在 之间beginWrite/endWrite
,并仅在传递给sync()
.
如您所见,这里我有一个原子存储,在beginWrite()
存储操作之后没有写入可以在存储之前重新排序。我没有找到合适的例子,而且我完全没有这方面的经验,所以我想确认一下它是可以的(通过测试验证也不容易)。
这段代码是无竞争的并且可以按我的预期工作吗?
如果我在每个原子操作中使用 std::memory_order_seq_cst ,我可以省略围栏吗?(即使是,我猜性能会更差)
我可以在 endWrite() 中放下围栏吗?
我可以在围栏中使用 memory_order_acq_rel 吗?我真的不明白其中的区别——我不清楚单一的总订单概念。
是否有任何简化/优化的机会?
+1。我很乐意接受任何更好的想法作为这个类的名称:)