I have a task scheduler implemented like this :
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 allows to block the background thread when there is no task available.
There is a race condition, if another thread remove all remaining tasks between “mNoTaskEvent.WaitOne()” and “lock (mTasks)”.
How could I atomically acquire the mTasks lock when leaving mNoTaskEvent.WaitOne() ?
Edit
The pthread API has a function that does exactly what I need : pthread_cond_wait
A simple fix for the race-condition would be to check the count again:
Using Monitor.Wait():
You would also need to Pulse() when stopping the whole chain.