Потокобезопасная реализация одноразового метода - PullRequest
1 голос
/ 30 января 2012

У меня есть метод, который нужно вызывать не более одного раза, например, Dispose.Теперь я понимаю, что это следующим образом:

private bool _isAlive = true;

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

Но это не потокобезопасно, потому что существует разрыв между сжатием и установкой флага _isAlive в false.Таким образом, возможно, что более одного потока выполнят код //Do Something.

Есть ли поточно-ориентированный вариант?

Ответы [ 2 ]

5 голосов
/ 30 января 2012

использование (обновлено в соответствии с комментариями):

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);
}

См. Ссылки http://msdn.microsoft.com/en-us/library/zs86dyzy.aspx

.

ОБНОВЛЕНИЕ (согласно комментарию от @LukeH):

Один CompareExchange вызов проще / лучше:

public void Dispose() 
{ 
if (Interlocked.CompareExchange(ref _isSomeMethodExecuted, 1, 0) == 0) 
{ /* main code of method */ } 
}
0 голосов
/ 30 января 2012

Использование MethodImpAttribute - самый простой способ ИМХО.

  public void Dispose()
  {
      if (isAlive && ShouldDispose())
      {
          //Your code here
      }
  }

  [MethodImplAttribute(MethodImplOptions.Synchronized)]
  private bool ShouldDispose()
  {
       if (isAlive)
       {
            isAlive = false;
            return true;
       }
       return false;
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...