2011-02-08 5 views
5

スレッドセーフリファレンスカウンタを実装する方法には、多大な疑問があります。 よく投票される答えは、「原子の増分/減分を使用する」です。 これは、refCounterを他のスレッドとの間で変更して読み書きする良い方法です。しかし。スレッドセーフリファレンスカウントに関する別の質問

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

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

Soが私はrefCounterを減らして安全に読む。しかし、もし私がそれをゼロと比較している間に、他のスレッドがrefCounterをインクリメントするのであれば?

私は間違っていますか?

EDIT:(例)

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; 

は私が間違っていますか?

+2

? 0の値は、文字通り「参照が残っていない」ことを意味します。 –

答えて

1

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

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

手動でオブジェクトを削除して無効にすることを避け、並行処理を意識したスマートポインタの実装を使用して、参照カウントを処理することをお勧めします。

ポインタが参照カウントをゼロと検出するたびに、新しい参照を初期化するためにdouble-checked lockingのように他のスレッドが参照しないようにオブジェクトをロックする必要があります。

+2

オブジェクトへの参照が残っていない場合、別のスレッドがオブジェクトにどのようにアクセスしますか? –

+1

@Jeremy、Antonが質問の例で述べたように、あるスレッドがRelease()メソッドを呼び出し、AtomicDecrement呼び出しの直後で、別のスレッドが参照を獲得しようとするdeleteステートメントの前に、refcountはゼロに等しくなりますが、スレッドは参照を取得し、削除の直前にrefcountをインクリメントし、refcount == 1のオブジェクトを削除します。これは不可能ではありませんが、不可能な場合です。 – vz0

+0

ありがとう。実際には、内部バッファではなく、スレッドセーフであるglobalStringを作成する際の問題です。ですから、vz0が提案するように、私はglobalStringを最初にロックしてから作業してください。 P.S.文字列は単なる例ですが、私の実際のコードでは、少し複雑な依存関係があります。 –

2

注意してください!

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

私はあなたの場合は

は、誰かがあなたの比較後にカウンタをインクリメントすることができることだけではありませんが、いくつかのスレッドがカウンターを得ることができます...かなり悪い終わるあなたの質問内の1つのようなコードを見てきました値が1で、その後は減少され、バッファや他のスレッドの使用削除メモリ... CRASHをDELETE

MY2Cそれはオブジェクトへの参照を持っていない場合、別のスレッドがカウンタをインクリメントするにはどうすればよい