与非线程安全资源并发



我有一个实现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. 如果_processingRequests false,请继续执行 lock 语句,一次只允许一个线程进入。进入块集_processingRequests的第一个线程true并启动工作线程。任何进入lock块的后续线程都将保释,因为_processingRequests现在true .

添加lock会直接引入不可接受的性能影响。

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

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

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

此外,一篇关于处理器上下文切换影响的博客文章,仔细检查锁定避免了不必要的情况。

带有

额外lock(_processLock)bool _processingRequests是无稽之谈。

使用适当的同步,例如 Monitor

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

这将要么完成工作,要么,如果_processLock已经被占用,则不执行(似乎您想要该行为),无需检查任何内容。

最新更新