我有一个实现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;
}
}
那是
- 检查(
bool
)_processingRequests
是否true
没有任何锁。如果它正在处理请求,请返回并确信工作线程正在运行。 - 如果
_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
已经被占用,则不执行(似乎您想要该行为),无需检查任何内容。