我有这段代码:
if (Monitor.TryEnter(_lock))
{
try
{
ExecuteTask();
}
finally
{
Monitor.Exit(_lock);
}
}
else
{
Monitor.Enter(_lock);
Monitor.Exit(_lock);
}
基本上,如果一个线程已经在执行任务,则以下线程应该等待它完成。 是否有一个适当的解决方案,而不是我发现的那个:
Monitor.Enter(_lock);
Monitor.Exit(_lock);
由于
答案 0 :(得分:1)
如果不需要阻止其他人,你可以使用它:
if (Monitor.TryEnter(_lock))
{
try
{
ExecuteTask();
}
finally
{
Monitor.Exit(_lock);
}
}
答案 1 :(得分:1)
我个人建议使用Monitor.Wait
和Monitor.PulseAll
添加_executing
标记的解决方案
Monitor.Enter(_lock);
if (_executing) { // Another thread is running ExecuteTask()
Monitor.Wait(_lock);
Monitor.Exit(_lock);
} else {
_executing = true;
Monitor.Exit(_lock);
try {
ExecuteTask();
} finally {
Monitor.Enter(_lock);
_executing = false;
Monitor.PulsaAll(_lock);
Monitor.Exit(_lock);
}
}
我认为这有点清洁:在您的解决方案中,持有锁意味着“我正在更新”以及“我只是等待另一个线程来完成更新”。这不是锁的“原始”目的(即管理对某些资源的独占访问)。
在我的解决方案中,锁用于管理对_executing
标志的独占访问。
还要注意原始代码可能有一个微妙的错误:我想在一个线程完成ExecuteTask()
之后,到达代码的下一个线程应该再次执行此操作。没想到这种情况:
ExecuteTask()
TryEnter
失败,线程转到else
分支并等待Monitor.Enter()
成功。ExecuteTask()
并释放锁Enter
是else
分支中的锁。现在:
Enter
和Exit
之间时,第三个线程到达代码。 TryEnter
失败(第二个线程持有锁),第三个线程进入else
分支。Exit
,第三个线程调用Enter
,第四个线程到达,尝试Enter
,转到else
分支。因此,有一种情况是没有其他线程调用ExecuteTask()
,所有后续线程都会直接进入else分支。
在您的具体情况下,这可能是不可能的,甚至是不可能的,但这样的例子通常指向并行编程时的设计缺陷。
答案 2 :(得分:0)
您可以使用TryEnter
的参数设置每个被阻止的线程等待的时间if (Monitor.TryEnter(_lock,TIMEOUT))//try to acquire lock for TIMEOUT miliseconds
{
try
{
//something
}
finally
{
Monitor.Exit(_lock);
}
}
else//lock was not acquired
{
//Handle TIMEOUT error
}