Reading List

The Selfish Gene
The Psychopath Test: A Journey Through the Madness Industry
Bad Science
The Feynman Lectures on Physics
The Theory of Everything: The Origin and Fate of the Universe


ifknot's favorite books »

Wednesday 5 March 2014

Part (2/3): A general purpose thread-safe internally synchronized message queue.

When it's time to end the relationship.

So here is the code for the single lock general purpose message queue as the obviously correct base queue type, but with one important addition...

The ability to close() the message queue.

But why?

TL;DR github.com/ifknot/libfbp



In multiprocessor programming, as in life, it is important to know when a relationship is over and the producer-consumer relationships of the AO, FBP and CSP approaches is no different.

Because an empty message queue does not mean the relationship between producer and consumer is necessarily over then another method of communicating when the producer(s) have finished is required.

A common approach is to send a specialised termination message as in Sutter's done message[1], the equivalent of the 0 in null terminated strings and the EOF marker for file streams.

But this permits any one producer to stop the communication whilst others may still be active.

An alternative approach is to allow the message queue to be closed with any subsequent attempt to perform a dequeue or enqueue action resulting in an exception being thrown!

The consumer is then able to carry on working inside a try-catch block until such time as the last producer has completed and detaches itself resulting in the closure of the message queue - after which time any further attempts at consuming results in the message queue specific runtime exception being caught and the consumer gracefully shutting down:
The general purpose requirement of the message_queue means that it must offer both bounded and unbounded behaviour with bounded try member functions as well as unbounded & waiting on empty member functions that permit dual usage:
Which results in the output:
So how do the bounded member functions work given the single queue mutex q_mutex?

The unbounded enqueue grows the queue automatically and the unbounded dequeue uses the single condition variable q_cv to wait if the queue is empty.
N.B. The q_cv.wait() is guarded by a while(q.empty) loop to trap any spurious wake up calls than can happen:

How can one now successfully share this message queue between multiple producers and consumers using a RAII idiom that automatically closes the queue if there are, either, no more interested consumers or no more interested producers?

What a good topic for the next blog entry...

References:
[1] Prefer Using Active Objects Instead of Naked Threads

No comments:

Post a Comment