1
Vote

Add Receive() and Sleep() with timeout.

description

Hi, sometimes I need a child Worker to wait with an answer (i.e. to be put to Sleep), but still be able to listen to Messages. And vice versa to do some job, when there are no messages in the queue.
Therefore I added the below two methods to the Worker class:
        /// <summary>
        /// Fetches a message from the message queue.
        /// This method blocks until there are any messages or 
        /// TimeSpan elapses.
        /// </summary>
        /// <returns>The first message in the queue or null 
        /// on time out.</returns>
        public Message Receive(TimeSpan ts) {
            Message msg = null;
            LinkedListNode<Message> msgNode;
            do {
                if (!_messageQueueWaitHandle.WaitOne(ts))
                    return null;
                lock (_messageQueue) {
                    msgNode = _messageQueue.First;
                    if (msgNode != null) {
                        msg = msgNode.Value;
                        _messageQueue.RemoveFirst();
                    }
                    if (msg == null) //nothing yet
                        _messageQueueWaitHandle.Reset();
                }
            }
            while (msg == null);
            return msg;
        }

        /// <summary>
        /// Sleeps until there are any messages or 
        /// TimeSpan elapses.
        /// </summary>
        /// <returns>true if there is a message in the queue
        /// or false on time out.</returns>
        public bool SoftSleep(TimeSpan ts) {
            return _messageQueueWaitHandle.WaitOne(ts);
        }

comments

HynekPetrak wrote Oct 23, 2013 at 11:00 AM

Correction for the above, as by default the _messageQueueWaitHandle is not Reset immediatelly, when a queue is emptied, but only on a subsequent Receive(...) call.
        public bool SoftSleep(TimeSpan ts) {
            lock (_messageQueue) {
                if (_messageQueue.Count == 0)
                    _messageQueueWaitHandle.Reset();
            }
            return  _messageQueueWaitHandle.WaitOne(ts);
        }