非原子型に対してstd :: atomic_refはどのように実装されていますか?


8

次のプロパティを適用するのはかなり難しいように思われるので、非アトミックオブジェクトに対してどのようにstd::atomic_ref効率的に(std::mutexオブジェクトごとに1 つ)実装できるのかと思います。

atomic_refを介してオブジェクトに適用されるアトミック操作は、同じオブジェクトを参照する他のatomic_refを介して適用されるアトミック操作に対してアトミックです。

特に、次のコード:

void set(std::vector<Big> &objs, size_t i, const Big &val) {
    std::atomic_ref RefI{objs[i]};
    RefI.store(val);
}

同じタイプのすべてのオブジェクトによって共有される大きなマスターロックでない限りstd::atomic_ref、同じものを毎回選択する必要があるため、実装は非常に難しいようstd::mutexです。

何か不足していますか?または、各オブジェクトは実装std::atomic_refを担当するため、アトミックであるか、std::mutex


2
おそらく、アドレスとミューテックスのマップと、オブジェクトのアドレスに関連するミューテックスの外観があります。これにより、複数の異なる参照で単一のオブジェクトを保護できます。
NathanOliver

回答:


5

実装はそれ自体とほとんど同じstd::atomic<T>です。これは新しい問題ではありません。

参照のstd ::アトミックのロックはどこにあるの? 典型的な実装std::atomic/ std::atomic_ref非ロックフリーオブジェクトのアドレスによってインデックス付けロックの静的ハッシュテーブル、、。ハッシュの衝突は、余分な競合を引き起こすだけで、正確性の問題にはなりません。(デッドロックは依然として不可能です。ロックは、一度に2を取得しようとしないアトミック関数によってのみ使用されます。)

たとえばGCC では、オブジェクトstd::atomic_refを呼び出すもう1つの方法__atomic_storeです。(を参照してください GCCマニュアル:アトミック組み込み関数を

コンパイラーは、 Tは、がロックフリーになるほど小さいいます。そうでない場合は、ロックを使用するlibatomicライブラリー関数を呼び出します。

(おもしろい事実:これは、オブジェクトにの十分なアラインメントがある場合にのみ機能することを意味しますatomic<T>。ただし、x86を含む多くの32ビットプラットフォームuint64_tでは、4バイトのアラインメントしかない場合があります。 atomic_refこのようなオブジェクトではコンパイルおよび実行されますが、実際にはアトミックではありません。コンパイラーは、32ビット・モードでSSE 8バイトのロード/ストアを使用してそれを実装します。幸いalignof(T) == sizeof(T)、64ビット・アーキテクチャーのほとんどのプリミティブ型のように、を持つオブジェクトには危険はありません。)


atomic<T>非原子型でも許可されていることに気づかなかった(mutexオブジェクトを所有しているため、技術的にそれ自体を割り当てることができるが)。説明をありがとう、それは理にかなっています。
Nonyme

6

実装では、オブジェクトのアドレスに基づくハッシュを使用して、操作の実行中に取得するロックのセットを決定できます。


これが実際にlibstdc ++がshared_ptrオブジェクトに対してアトミック操作を実装する方法です。github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/src/...
ブライアン・

上記のハッシュテーブルにはミューテックスが含まれますか?彼らはいつ解放しても安全ですか?
Nonyme

@Nonyme私が提供したリンクでは、静的な保存期間があることがわかります。
ブライアン、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.