5

アトミック操作で共有ポインタを安全に管理する方法を正確に理解しようとしています。VC11(Visual studio 2012)はC ++ 11をサポートしているため、std::shared_ptrでの読み取り/書き込みレースを許可できます。基本を理解したことを確認してから、VC11のstd::shared_ptrでのアトミック操作の実装の詳細について質問します。

std::shared_ptr<A> x, y, z;
x = std::make_shared<A>(args1);
y = std::make_shared<A>(args2);

スレッド1

std::shared_ptr<A> temp = std::atomic_load(y);

スレッド2

std::atomic_store(&y, z);

アトミックがないと、競合によってtemp状態が破損する可能性があります。または、スレッド1がshared_ptrをコピーして追加しようとしたときに、スレッド2が元のyが指すAインスタンスを削除する可能性があります。 「ゾンビ」オブジェクト。

VC11のatomic_loadとatomic_storeに関する私の質問:

グローバル変数でテストアンドセットを実行するスピンロックを使用していることに気づきました。だから私は疑問に思いました:shared_ptr自体の参照カウンターの一番上のビットでテストアンドセットをしてみませんか?そうすれば、異なるshared_ptrのロックが互いに競合することはありません。これが行われなかった理由はありますか?

編集:VSの実装atomic_is_lock_free。すべてにスピンロックを使用しているので、当然のことです。なぜグローバルロックの代わりにshared_ptr-instance-specificロックを使用させることができなかったのか疑問に思っています。

template <class _Ty> inline
bool atomic_is_lock_free(const shared_ptr<_Ty> *)
{   // return true if atomic operations on shared_ptr<_Ty> are lock-free
    return (false);
}
4

2 に答える 2

3

ref カウントは shared_ptr の制御ブロックに格納されているため、shared_ptr の ref カウントに対してアトミックなテスト アンド セットを実行することはできません。テスト アンド セットを試行するまでに、別のスレッドが最後の shared_ptr 参照を解放し、制御ブロックを削除している可能性があります。

Thread 1                                  Thread 2
Read control block address

                                          Decrement ref count (now 0)
                                          Delete control block

Test-and-set ref count (undefined behaviour)

ここでの前提は、複数のスレッドが同じshared_ptr インスタンスを操作していることです。各スレッドが独自のインスタンス (同じ制御オブジェクトを指している) を持っている場合、問題はなく、アトミックな shared_ptr 操作は必要ありません。

于 2015-06-02T01:27:20.463 に答える
1

参照カウントの最上位ビットを変更するには、その最上位ビットを無視するカウンターとして参照カウントを処理するコードが必要になります。つまり、あまり一般的でないケースでわずかな速度の増加を提供するために、最も一般的な使用を遅くします。

于 2013-03-09T14:28:13.363 に答える