c#concurrency - 监控

时间:2015-08-13 15:37:29

标签: c# multithreading

我有这段代码:

if (Monitor.TryEnter(_lock))
{
    try
    {
        ExecuteTask();
    }
    finally
    {
        Monitor.Exit(_lock);
    }
}
else
{
    Monitor.Enter(_lock);
    Monitor.Exit(_lock);
}

基本上,如果一个线程已经在执行任务,则以下线程应该等待它完成。 是否有一个适当的解决方案,而不是我发现的那个:

    Monitor.Enter(_lock);
    Monitor.Exit(_lock);

由于

3 个答案:

答案 0 :(得分:1)

如果不需要阻止其他人,你可以使用它:

if (Monitor.TryEnter(_lock))
{
    try
    {
        ExecuteTask();
    }
    finally
    {
        Monitor.Exit(_lock);
    }
}

答案 1 :(得分:1)

我个人建议使用Monitor.WaitMonitor.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()并释放锁
  • 第二个帖子Enterelse分支中的锁。

现在:

  • 当第二个线程在EnterExit之间时,第三个线程到达代码。 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
}