1

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

  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

4

1 回答 1

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()。

于 2012-04-23T08:47:50.620 回答