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 に答える