5

スレッド セーフな参照カウンターを実装する方法については、たくさんの質問があります。そして、よく投票された答えは、「アトミックインクリメント/デクリメントを使用する」です。わかりました。これは、他のスレッドが途中で変更することなく、refCounter を読み書きするための良い方法です。しかし。

私のコードは次のとおりです。

void String::Release()
{
    if ( 0 == AtomicDecrement( &refCounter ) ) )
        delete buffer;
}

そう。安全にrefCounterをデクリメントして読み取ります。しかし、私が refCounter をゼロと比較しているときに、他のスレッドが私の refCounter を INCREMENT するとどうなるでしょうか????

私が間違っている?

編集:(例)

String* globalString = new String(); // refCount == 1 after that.

// thread 0:
delete globalString; 
  // This invokes String::Release().
  // After AtomicDecrement() counter becomes zero. 
  // Exactly after atomic decrement current thread switches to thread 1.

// thread 1:
String myCopy = *globalString;
  // This invokes AddRef(); 
  // globalString is alive;
  // internal buffer is still not deleted but refCounter is zero;
  // We increment and switch back to thread 0 where buffer will be 
  // succefully deleted;

私が間違っている?

4

2 に答える 2

2

気をつけて !

より大きなもののライフサイクルを管理する参照カウンターのような変数を保護するだけでは不十分です。

あなたの質問のようなコードがかなり悪い結果になるのを見たことがあります...

あなたの場合、誰かが比較後にカウンターをインクリメントできるだけでなく、一部のスレッドが値1のカウンターを取得できるため、バッファーをデクリメントしてDELETEし、他のスレッドが削除されたメモリを使用します...クラッシュ

my2c

于 2011-02-08T16:20:52.017 に答える
1

あなたの例は私には正しく聞こえます。

ただし、ここでの問題はアトミック操作に関するものではなく、オブジェクトを手動で削除し、すぐに削除されるオブジェクトを参照することです。参照カウントが 1 ではなく 8 の場合はどうなるでしょうか。

オブジェクトを手動で削除したり無効にしたりしないようにする必要があります。また、同時実行性を認識したスマート ポインターの実装を使用して、参照カウントを処理することをお勧めします。

ポインターが refcount がゼロであることを検出するたびに、新しい参照を初期化するためのダブルチェック ロックと同様に、オブジェクトをロックして他のスレッドから参照されないようにする必要があります。

于 2011-02-08T16:17:52.220 に答える