离开WaitOne时获取锁定

时间:2012-04-23 08:42:35

标签: c# locking atomic

我有一个像这样实现的任务调度程序:

  private readonly List<Task> mTasks = new List<Task>();
  private readonly ManualResetEvent mNoTaskEvent = new ManualResetEvent(false);

  public void AddTask(Task task)
  {
     lock (mTasks)
     {
        mTasks.Add(task);
        mNoTaskEvent.Set();
     }
  }

  public void RemoveTask(Task task)
  {
     lock (mTasks)
     {
        mTasks.Remove(task);
        if (mTasks.Count == 0)
           mNoTaskEvent.Reset();
     }
  }

  void BackgroundThreadProc()
  {
     while (mRunning)
     {
        mNoTaskEvent.WaitOne();

        if (!mRunning) break;

        Task nextTask;

        lock (mTasks)
        {
           mTasks.Sort(...);
           nextTask = mTasks.First();
        }

        nextTask.Run();
     }
  }

mNoTaskEvent允许在没有可用任务时阻止后台线程。 如果另一个线程删除“mNoTaskEvent.WaitOne()”和“lock(mTasks)”之间的所有剩余任务,则存在竞争条件。

离开mNoTaskEvent.WaitOne()时,如何以原子方式获取mTasks锁?

修改 pthread API具有完全符合我需要的功能:pthread_cond_wait

1 个答案:

答案 0 :(得分:1)

竞争条件的一个简单修复方法是再次检查计数:

    lock (mTasks)
    {
       if (mTasks.Count < 1)
         continue;

       mTasks.Sort(...);
       nextTask = mTasks.First();
    }

使用Monitor.Wait():

 while (mRunning)
 {
    //mNoTaskEvent.WaitOne();

    if (!mRunning) break;

    Task nextTask;

    lock (mTasks)
    {
        while (mTasks.Count < 1)
        {
           Monitor.Wait(mTasks);

           if (!mRunning) break;                
        }

        ...     
    }



public void AddTask(Task task)
{
  lock (mTasks)
  {
     mTasks.Add(task);
     //mNoTaskEvent.Set();
     Monitor.Pulse(mTasks);
  }
}

当停止整个链时,你还需要Pulse()。