Waking a thread from sleep when the collection changes

I have a method that works in a queue. After the first object in the queue is used, it goes to sleep for a predefined period (for example, 10 seconds). Is there a way to wake up this thread if the queue is changed by some other thread in the third or fourth second?

+3


source to share


6 answers


Thank you all for the suggested options. I finally settled on AutoResetEvent for this requirement. After using the first object in the queue, instead of putting the main thread in "Sleep", I spawned a new thread from the main thread, where I called sleep. The main thread will just wait. As soon as the new thread wakes up, it will signal the main thread using Set and the main thread will resume. This is one part.

Second part. If any other thread changes the queue, even that thread calls Set on the same EventWaitHandle, thereby resuming the main thread again.



This may not be the optimal solution, but simpler than other approaches.

0


source


You should use a collection specifically designed for this purpose. One example is BlockingCollection

which allows you to take an item from a collection, and if there are no items to be accepted, the method will block until the item is provided to you. It is also a collection specially designed to handle multiple threads, lightening your sync load.



Note that it BlockingCollection

can be initialized to support different collection types. It will use it by default ConcurrentQueue

, but there are other collections in the namespace System.Collections.Concurrent

that you can use if you don't need the semantics of the queue (you seem to do that). You can also implement your own collection implementing IProducerConsumerCollection<T>

if you really need something unique.

+5


source


Instead of Thread.Sleep

:

You can use Monitor.Wait

with a timeout, and you can use Monitor.Pulse

to wake it up if you need from any thread.

Really good example / explanation here

0


source


I would recommend against using it anyway Thread.Sleep()

, because it blocks the thread entirely.

It is much better to use AutoResetEvent

or ManualResetEvent

to synchronize two or more threads:

https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx

0


source


Servy has the correct answer for this using a Blocking Collection .

Just add another one: it creates a new thread with an empty thread when the "work" items become available in the queue and processes them asynchronously on that thread.

You can use it in a producer / consumer queue:

eg:.

/// <summary>
/// Producer/consumer queue. Used when a task needs executing, it’s enqueued to ensure order, 
/// allowing the caller to get on with other things. The number of consumers can be defined, 
/// each running on a thread pool task thread. 
/// Adapted from: http://www.albahari.com/threading/part5.aspx#_BlockingCollectionT
/// </summary>
public class ProducerConsumerQueue : IDisposable
{
    private BlockingCollection<Action> _taskQ = new BlockingCollection<Action>();

    public ProducerConsumerQueue(int workerCount)
    {
        // Create and start a separate Task for each consumer:
        for (int i = 0; i < workerCount; i++)
        {
            Task.Factory.StartNew(Consume);
        }
    }

    public void Dispose() 
    { 
        _taskQ.CompleteAdding(); 
    }

    public void EnqueueTask(Action action) 
    { 
        _taskQ.Add(action); 
    }

    private void Consume()
    {
        // This sequence that we’re enumerating will block when no elements
        // are available and will end when CompleteAdding is called.
        // Note: This removes AND returns items from the collection.
        foreach (Action action in _taskQ.GetConsumingEnumerable())
        {
            // Perform task.
            action();
        }
    }
}

      

0


source


I would put the thread into iteration while

and then reduce the sleeptimer to about 200 milliseconds.

But on each iteration, I checked if the queue had changed. Thus, the thread is constantly in sleep mode and wakes up when the queue has been changed.

If you want to stop the thread, you just set the condition while

to false

.

-1


source







All Articles