[muscle] Re: Thread-safe queues

  • From: Jeremy Friesner <jaf@xxxxxxxxxxxx>
  • To: muscle@xxxxxxxxxxxxx
  • Date: Mon, 21 Feb 2005 10:23:59 -0800

Hi Paal,

Let me answer your questions in reverse order... :^)

> I also want to use SendMessageToSessions() in another thread than the one
> where my Win32MessageTransceiverThread-loop is running.

The MessageTransceiverThread class is designed to co-ordinate just two
threads:  the I/O thread which the MessageTransceiverThread class creates and 
holds internally, and the user thread that is holding the 
MessageTransceiverThread object (i.e. your Win32 thread in this case).  

Trying to call methods directly on the MessageTransceiverThread object from a
third thread is probably not a good idea.  A better technique would be to have 
the third thread send a MessageRef to your Win32 thread, and then your Win32 
thread could forward that MessageRef on to the MessageTransceiverThread (by 
calling SendMessageToSessions() on it).

A good way to send MessageRefs between threads is to implement your threads 
using the MUSCLE Thread class -- that way, the thread-safe MessageRef queues 
are all set up and handled for you.  (Note that MessageTransceiverThread 
itself subclasses the Thread class, so MessageTransceiverThread is an example 
of how to do this -- it subclasses the Thread class to create a thread that 
does network I/O, but if you need to have threads that do other things, you 
can just subclass from the Thread class directly, and override 
MessageReceivedFromOwner() with code to handle the MessageRefs that you send 
to that thread.  Then messaging is easy -- your main thread just calls 
SendMessageToInternalThread() to send a MessageRef to the internal thread, 
and the internal thread can call SendMessageToOwner() to send a MessageRef 
back to the main thread.  (One caveat is that if you want your Win32 thread 
to be woken up to receive the MessageRef from your internal thread, you will 
need to override Thread::SignalOwner() to call SetEvent() or 
PostThreadMessage(), similar to what is done in  
Win32MessageTransceiverThread::SignalOwner())

On Monday 21 February 2005 05:31, Paal Grana wrote:
> Is it possible to use a Queue object from two different threads like this:
[...]
> I want to send data from one thread to another (producer - consumer )
> using a Queue.

No -- the Queue class wasn't designed to be thread safe.  (Same goes for  
Hashtable and Message, btw).  If for some reason you need to access a Queue's 
methods directly from multiple threads, you will need to serialize access to 
the Queue to avoid data corruption.

> Will I have to use EnterCriticalSection() around RemoveHead/AddTail?

You could use that, but a better solution would be to use a muscle Mutex 
object and call Lock()/Unlock() on it.  (And a better solution than that 
would be to use the Thread class as described above... or at least examine 
the MessageRef-handling code in the Thread class to get a feel for what needs 
to be done)

> I have run into problems doing this and the reason seems to be
> multi-threading related.

Multi-threading is tricky to get 100% correct, so good luck... my advice is to 
re-use muscle's threading APIs as much as possible, as they have already been 
debugged and tested and work well on all supported platforms (AFAIK).

Jeremy

Other related posts: