简体   繁体   中英

Thread-safe replace for code?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM