与非线程安全资源的并发

时间:2016-03-15 09:34:16

标签: c# .net multithreading concurrency

我有一个实现async方法的多线程应用程序。该应用程序利用非线程安全的资源,并且需要在单个线程上使用。工作线程像这样被保护

private void EnsureWorkerIsRunning()
{
    // first try without lock
    if (_processingRequests)
    {
        return;
    }
    lock (_processLock)
    {
        // try again without lock
        if (_processingRequests)
        {
            return;
        }
        _processingRequests = true;
        DoWork();
        _processingRequests = false;
    }
}

那是

  1. 检查(bool_processingRequests是否true没有任何锁定。如果正在处理请求,请返回并确信工作人员正在运行。
  2. 如果_processingRequestsfalse,请继续执行lock语句,一次只允许一个帖子输入。进入块集的第一个线程_processingRequeststrue并启动工作线程。任何进入lock块的后续线程都会保释,因为_processingRequests现在是true
  3. 直接添加lock会导致无法接受的性能损失。

    我正在寻找一种更优雅的方式来实现同样的目标,而不会影响性能。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

带有额外bool _processingRequests

lock(_processLock)是无意义的。

使用适当的同步,例如Monitor

object _processLock = new object();

// acquiring lock,
if(Monitor.TryEnter(_processLock)) // if already acquired - exit immediately(return false)
    try
    {
        ...
    }
    finally { Monitor.Exit(_processLock); }

这可以做好工作,或者如果_processLock已经被占用,就不要做(似乎你想要这种行为),不需要检查任何事情。

答案 1 :(得分:1)

您正在使用的技术称为Double-checked locking,在适当的情况下使用非常精细。它被广泛使用,它与优雅无关,因为它的主要目的是在每次输入lock语句时减少性能下降,并额外检查没有锁定的条件。

但是在您的特定情况下,更适合仅使用Monitor.TryEnter,如果某个线程已经获得锁定,则返回false

此外,blog post关于处理器上下文切换的影响,双重检查锁定避免了不必要的地方。