0

unordered_map文字列キーとバリアント値を使用して、いくつかの設定を格納するオブジェクトがあります。私のライブラリは複数のスレッドから使​​用される可能性があり、読み取りが書き込みを大幅に上回る可能性が非常に高いため、「get」操作がロックフリーで「put」操作がクリティカルなコピーオンライト実装について考えました。セクション、例のように:

class Cfg {
    using M = unordered_map<string,X>;
    shared_ptr<const M> data;
    mutex write_lock;
public:
    X get(string key) {
        shared_ptr<const M> cur_ver = atomic_load_explicit(&data, memory_order_acquire);
        // Extract the value from the immutable *cur_ver
    }
    void put(string key, X value) {
        lock<muted> wlock(write_lock);
        // No need for the atomic load here because of the lock
        shared_ptr<const M> cur_ver = data;
        shared_ptr<const M> new_ver = ;// create new map with value included
        // QUESTION: do I need this store to be atomic? Is it even enough?
        atomic_store_explicit(&data, new_ver, memory_order_release);
    }
}

取得/解放の同期がポインター値だけでなく、ポイント先のデータにも影響を与える限り、設計が機能することはかなり確信しています。ただし、私の質問は次のとおりです。

  • これが機能するには、ロック内のアトミック ストアが必要ですか?
  • それとも、アトミックな取得は、「解放」操作であるミューテックスのロック解除と同期しますか?
4

2 に答える 2

1

get関数が常に最新の値を返すようにする場合は必須です。同じクロック タイムで複数の読み取りと書き込みが発生する場合があります。アトミック メモリ順序を使用すると、書き込み順序が読み取り前になることが保証されます。

非アトミック ストアとアトミック ロードを混在させると、未定義の動作になります。このスレッドでも議論されました。別の書き込みの後に書き込みを行う可能性があります。非アトミック命令を使用すると、データ競合が発生する可能性があります。

cppreferenceによると

memory_order_acquire

操作は、(読み込みスレッドに目に見える副作用がある) 解放スレッドのメモリへのすべてのアクセスが発生した後に発生するように命令されます。

memory_order_release

この操作は、消費または取得操作の前に発生するように命令され、ロード スレッドに目に見える副作用をもたらす可能性のあるメモリへの他のアクセスの同期ポイントとして機能します。

于 2020-06-09T00:04:16.130 に答える