While working on a large project I realized I was making a lot of calls to be scheduled in the future. Since these were fairly light-weight, I thought it might be better to use a separate scheduler.
ThreadPool.QueueUserWorkItem (() => 
{
    Thread.Sleep (5000);
    Foo (); // Call is to be executed after sometime
});
So I created a separate scheduler class that runs on its own thread and executes these events. I have 2 functions that access a shared queue from separate threads. I'd use a lock, but since one of the threads needs to sleep-wait, I wasn't sure how to release the lock.
class Scheduler
{
    SortedDictionary <DateTime, Action> _queue;
    EventWaitHandle _sync;
    // Runs on its own thread
    void Run ()
    {
        while (true)
        {
            // Calculate time till first event
            // If queue empty, use pre-defined value
            TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
            // Execute action if in the next 100ms
            if (timeDiff < 100ms)
                ...
            // Wait on event handle for time
            else
                _sync.WaitOne (timeDiff);
        }
    }
    // Can be called by any thread
    void ScheduleEvent (Action action, DataTime time)
    {
        _queue.Add (time, action);
        // Signal thread to wake up and check again
        _sync.Set ();
    }
}
The problem is easily solved, make sure the WaitOne is outside the lock.
  //untested
  while (true)
  {
      Action doit = null;
      // Calculate time till first event
      // If queue empty, use pre-defined value
      lock(_queueLock)
      {
         TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
         if (timeDiff < 100ms)
            doit = _queue.Dequeue();
      }
      if (doit != null)
        // execute it
      else
         _sync.WaitOne (timeDiff);
  }
_queueLock is a private helper object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With