2012-04-23 2 views
1

У меня есть планировщик задач реализован так:замок Приобретать при выходе WaitOne

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)».

Как я мог атомарно получить блокировку mTasks при выходе из mNoTaskEvent.WaitOne()?

Edit потоковой API имеет функцию, которая делает именно то, что мне нужно: pthread_cond_wait

+0

Вы смотрели 'Monitor.Wait()' для этого? –

+0

Да, но я не понимаю, как это может мне помочь, у вас есть идея? – Julien

+0

Он заменит ResetEvent, а не увеличит его. –

ответ

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() при остановке всей цепочки.

+0

Да, конечно :-), но цель этого вопроса - найти более элегантное решение общей проблемы, чем для этого реального случая. – Julien

+0

Я не уверен, что существует «элегантное решение общей проблемы». –

+0

Я искал что-то вроде функции C «pthread_cond_wait», которая делает [1] освобождение принадлежащего мьютексу и ожидания при условии [2]. Пробуждение и получение мьютекса, 1 и 2 являются атомарными. Ваше решение с монитором довольно приятно, спасибо! – Julien

Смежные вопросы