2012-01-30 4 views
1

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

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) ... особенно с учетом того, что у Вас есть получил практически тот же ответ на оба вопроса. –

+0

@AndrewBarber не совсем ... вопрос, с которым вы связаны, схож, но касается только защиты от повторного размещения (т. Е. Нескольких исполнений параллельно) ... этот вопрос касается одноразового исполнения всего объекта жизни , – Yahia

+0

Кстати, вы совершенно неправильно описываете свое требование. Дело не в том, что 'Dispose()' нужно вызывать не более одного раза, это почти точно противоположно: 'Dispose()' * must * может безопасно обрабатывать вызов более одного раза. –

ответ

5

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

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

Для refrences см http://msdn.microsoft.com/en-us/library/zs86dyzy.aspx

UPDATE (в соответствии с комментарием от @LukeH):

Один CompareExchange вызов является более простым/лучше:

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

Если метод будет называться много раз - «Do что-то "может быть много раз использовано – Vasya

+0

@ Praetor12 no ... вы можете вызвать метод много раз, но только первый раз на самом деле будет выполнять код в« Главном коде метода », любые последующие вызовы просто ничего не сделают ... – Yahia

+0

@Yahia: Это будет вызвано в первый раз * и * каждый (2 ** 64)-й звонок после этого! – LukeH

0

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

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

    [MethodImplAttribute(MethodImplOptions.Synchronized)] 
    private bool ShouldDispose() 
    { 
     if (isAlive) 
     { 
      isAlive = false; 
      return true; 
     } 
     return false; 
    } 
Смежные вопросы