11

Producer-consumer with a variation - How to synchronize with thread signal / wai...

 2 years ago
source link: https://www.codesd.com/item/producer-consumer-with-a-variation-how-to-synchronize-with-thread-signal-wait.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Producer-consumer with a variation - How to synchronize with thread signal / wait?

advertisements

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 trouble is, I'm not sure how to synchronize access to the queue between the 2 functions. I can't use a monitor or mutex, because Run() will sleep-wait, thus causing a deadlock. What is the right synchronization mechanism to use here? (If there a mechanism to atomically start the sleep-wait process and immediately release the lock, that might solve my problem)
  • How can I verify there is no race-condition?
  • Is this a variation of the producer consumer problem, or is there a more relevant synchronization problem-description?

    While this is somewhat geared towards C#, I'd be happy to hear a general solution to this. Thanks!


OK, take 2 with Monitor/Pulse.

    void Run ()
    {
        while (true)
        {
            Action doit = null;

            lock(_queueLock)
            {
                while (_queue.IsEmpty())
                    Monitor.Wait(_queueLock);

                TimeSpan timeDiff = _queue.First().Key - DateTime.Now;
                if (timeDiff < 100ms)
                    doit = _queue.Dequeue();
            }

            if (doit != null)
                ; //execute doit
            else
             _sync.WaitOne (timeDiff);
        }
    }

void ScheduleEvent (Action action, DataTime time)
{
    lock (_queueLock)
    {
        _queue.Add(time, action);
        // Signal thread to wake up and check again
        _sync.Set ();
        if (_queue.Count == 1)
             Monitor.Pulse(_queuLock);
    }
}




About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK