In process of developing I often face with the next problem: if some method is already executed by one thread - method is must not be executed by another thread. Another thread must do nothing - simple exit from method, beacuse of it I can't use "lock". Usually, I solve this problem like that:
private bool _isSomeMethodExecuted = false;
public void SomeMethod ()
{
if (!this._isSomeMethodExecuted) //check if method is already executed
{
this._isSomeMethodExecuted = true;
//Main code of method
this._isSomeMethodExecuted = false;
}
}
But this code is not thread-safe: if one thread execute condition statement but It be stopped before set flag in true and another thread can execute condition - then both threads are inside method code.
Is there any thread-safe replace for it?
the following is thread-safe and does not block if the method is already executing - even if it is alreasy executing on the same thread... which provides protection from reentrancy for all scenarios.
private long _isSomeMethodExecuted = 0;
public void SomeMethod ()
{
if (Interlocked.Increment (ref this._isSomeMethodExecuted) == 1) //check if method is already executed
{
//Main code of method
}
Interlocked.Decrement (ref this._isSomeMethodExecuted);
}
For refrences see http://msdn.microsoft.com/en-us/library/zs86dyzy.aspx
Monitor
does this job for you, but the lock is thread-wide (and therefore open for recursive calls!). The lock
statement uses a Monitor
too (using the blocking Enter
method), but you may work with the TryEnter
method instead:
if(Monitor.TryEnter(myLockObject))
{
try
{
DoSomething(); // main code
}
finally
{
Monitor.Exit(myLockObject);
}
}
TryEnter does not block but returns a bool
indicating whether the lock was successfully acquired or not.
If you want recursive calls not to enter the main code block again, you should use a semaphore instead. Semaphores use counters instead of locking objects, so you cannot reenter even from the same thread:
class Program
{
private static Semaphore sem = new Semaphore(1, 1);
static void Main(string[] args)
{
MyMethod();
MyMethod();
}
private static void MyMethod()
{
if(sem.WaitOne(0))
{
try
{
Console.WriteLine("Entered.");
MyMethod(); // recursive calls won't re-enter
}
finally
{
sem.Release();
}
}
else
{
Console.WriteLine("Not entered.");
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.