线程安全替换代码?

时间:2012-01-30 08:48:14

标签: c# .net multithreading thread-safety

在开发过程中我经常遇到下一个问题:如果某个方法已经由一个线程执行 - 方法不能被另一个线程执行。另一个线程必须什么都不做 - 简单退出方法,因为它我不能使用“锁定”。通常,我这样解决这个问题:

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

但是这段代码不是线程安全的:如果一个线程执行条件语句但是在set flag为true之前停止,而另一个线程可以执行条件 - 那么两个线程都在方法代码中。

是否有任何线程安全替代品?

2 个答案:

答案 0 :(得分:2)

以下是线程安全的,并且如果该方法已在执行,则不会阻止 - 即使它在同一个线程上执行也很容易...这可以防止所有场景的重入。

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

参考http://msdn.microsoft.com/en-us/library/zs86dyzy.aspx

答案 1 :(得分:1)

Monitor为你完成这项工作,但锁是线程范围(因此可以打开递归调用!)。 lock语句也使用Monitor(使用阻止Enter方法),但您可以改为使用TryEnter方法:

    if(Monitor.TryEnter(myLockObject))
    {
       try
       {
           DoSomething(); // main code
       }
       finally
       {
           Monitor.Exit(myLockObject);
       }
    }

TryEnter不会阻止,但会返回bool,表示是否已成功获取锁定。

如果您希望递归调用不再输入主代码块,则应使用信号量。信号量使用计数器而不是锁定对象,因此您甚至无法从同一个线程重新进入:

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