2012-01-30 3 views
1

私はメソッドを持っています。これは、例えば、Disposeのように1回だけ呼び出さなければなりません。1回限りのメソッドのスレッドセーフな実装

private bool _isAlive = true; 

public void Dispose() 
{ 
    if (this._isAlive) 
    { 
     this._isAlive = false; 
     //Do Something 
    } 
} 

しかしcomprasionと偽にフラグ_isAlive設定の間に隙間があるので、それはスレッドセーフではありません。今、私は次のようにそれを実現しています。したがって、複数のスレッドが//Do Somethingコードを実行する可能性があります。

スレッドセーフなバリアントはありますか?

+0

可能重複[スレッドセーフなコードを置き換える?](http://stackoverflow.com/questions/9061311/thread-safe-replace-for-code)...特にあなたがきたことを考えると

public void Dispose() { if (isAlive && ShouldDispose()) { //Your code here } } [MethodImplAttribute(MethodImplOptions.Synchronized)] private bool ShouldDispose() { if (isAlive) { isAlive = false; return true; } return false; } 
両方の質問について本質的に全く同じ答えを得た。 –

+0

@AndrewBarber正確には...あなたがリンクしている質問は似ていますが、リエントラント(つまり、複数の実行を並行して)からの保護しか扱っていません...この質問は、オブジェクトの全ライフタイム。 – Yahia

+0

ちなみに、あなたはあなたの要求を完全に間違って記述しています。 'Dispose()'は何度も呼び出されなければならないということではなく、ほぼ逆のことです: 'Dispose()' *は、複数回呼び出されることを安全に処理できなければなりません。 –

答えて

5

(コメントに従って更新)使用:refrencesについては

private long _isSomeMethodExecuted = 0; 

public void Dispose() 
{ 
if (Interlocked.Read (ref this._isSomeMethodExecuted) != 0) 
     return; 

if (Interlocked.Increment (ref this._isSomeMethodExecuted) == 1) //check if method is already executed 
{ 
     //Main code of method 

} 
// leave the decrement out - this leads to 
// this method being callable exactly once as in the lifetime of the object 
// Interlocked.Decrement (ref this._isSomeMethodExecuted); 
} 

は(@LukeHからのコメントあたりなど)http://msdn.microsoft.com/en-us/library/zs86dyzy.aspx

UPDATE参照:

を単一CompareExchange呼び出しが簡単です/より良い:

public void Dispose() 
{ 
if (Interlocked.CompareExchange(ref _isSomeMethodExecuted, 1, 0) == 0) 
{ /* main code of method */ } 
} 
+0

メソッドは何度も何度も呼び出される - 何か "何度も呼び出すことができます – Vasya

+0

@ Praetor12 no ...あなたはメソッドを何度も呼び出すことができますが、初めての場合はメソッドのメインコードでコードを実行しますが、連続する呼び出しは何もしません。 – Yahia

+0

@ヤヒヤ:それは最初に呼び出される*とそれ以降のすべての(2 ** 64)コール! – LukeH

関連する問題