Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking a Queue<T> Continuously

I would like a function to check a Queue for new additions continuously on one thread

Obviously there is the option of a continuous loop with sleeps, but I want something less wasteful.

I considered a wait handle of some type and then having the queue signal it, but I can't override Enqueue safely as it is not virtual.

Now I'm considering encapsulating a Queue<T> as my best option but I wanted to ask you fine folks if there were a better one!

The idea is: I want many threads to access a socket connection while guaranteeing they read only the response for their message, so I was going to have one thread dispatch and read responses and then execute a callback with the response data (in plain text)

like image 256
Ben Avatar asked Apr 21 '11 04:04

Ben


1 Answers

Try the blocking queue: Creating a blocking Queue<T> in .NET?

The basic idea is that when you call TryDequeue it will block until there is something in the queue. As you can see "beauty" of the blocking queue is that you don't have to poll/sleep or do anything crazy like that... it's the fundamental backbone for a Producer/Consumer pattern.

My version of the blocking queue is:

public class BlockingQueue<T> where T : class
{
    private bool closing;
    private readonly Queue<T> queue = new Queue<T>();

    public int Count
    {
        get
        {
            lock (queue)
            {
                return queue.Count;
            }
        }
    }

    public BlockingQueue()
    {
        lock (queue)
        {
            closing = false;
            Monitor.PulseAll(queue);
        }
    }

    public bool Enqueue(T item)
    {
        lock (queue)
        {
            if (closing || null == item)
            {
                return false;
            }

            queue.Enqueue(item);

            if (queue.Count == 1)
            {
                // wake up any blocked dequeue
                Monitor.PulseAll(queue);
            }

            return true;
        }
    }


    public void Close()
    {
        lock (queue)
        {
            if (!closing)
            {
                closing = true;
                queue.Clear();
                Monitor.PulseAll(queue);
            }
        }
    }


    public bool TryDequeue(out T value, int timeout = Timeout.Infinite)
    {
        lock (queue)
        {
            while (queue.Count == 0)
            {
                if (closing || (timeout < Timeout.Infinite) || !Monitor.Wait(queue, timeout))
                {
                    value = default(T);
                    return false;
                }
            }

            value = queue.Dequeue();
            return true;
        }
    }

    public void Clear()
    {
        lock (queue)
        {
            queue.Clear();
            Monitor.Pulse(queue);
        }
    }
}

Many thanks to Marc Gravell for this one!

like image 183
Kiril Avatar answered Oct 31 '22 05:10

Kiril