如何避免同时调用方法而不阻塞?

时间:2016-02-23 09:26:09

标签: c# multithreading synchronization locking nonblocking

我想运行一个可能运行几秒钟的清理任务。多个线程可以调用此任务,但我只想运行此任务一次。所有其他的调用都应该跳过。

以下是我目前的实现,但我无法想象.net框架中没有更好的解决方案,从而减少了代码行。

    object taskLock;
    bool isRunning;

    void Task()
    {
        if (isRunning) return;

        try
        {
            lock (taskLock)
            {
                if (isRunning) return;
                isRunning = true;
            }
            // Perform the magic
        }
        finally
        {
            isRunning = false;
        }
    }

1 个答案:

答案 0 :(得分:1)

是的,有更好的解决方案。您可以使用Interlocked.CompareExchange,代码变得更简单,无锁:

class Worker
{
    private volatile int isRunning = 0;

    public void DoWork()
    {
        if (isRunning == 0 && Interlocked.CompareExchange(ref isRunning, 1, 0) == 0)
        {
            try
            {
                DoTheMagic();
            }
            finally
            {
                isRunning = 0;
            }
        }
    }

    private void DoTheMagic()
    {
        // do something interesting
    }
}

在这种情况下,Interlocked.CompareExchange执行以下操作作为原子操作(伪代码):

wasRunning = isRunning;
if isRunning = 0 then 
     isRunning = 1
end if
return wasRunning

来自MSDN文档:

public static int CompareExchange(
    ref int location1,
    int value,
    int comparand
)
  

如果comparand和location1中的值相等,则值为   存储在location1中。否则,不执行任何操作。比较   和交换操作作为原子操作执行。该   CompareExchange的返回值是location1中的原始值,   是否进行交换