ベアボーンで実行されていたプロジェクトを 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。このクラスの名前として、より良いアイデアを喜んで受け入れます:)