views:

139

answers:

4

I have a design question. Is it better to define separate classes for SENDING and RECEIVING. Or, is it better to define a single Thread class? I like the idea of a single Thread class because it is easier to share a queue which can be locked by mutex.

Design Option #1 (Separate):

mySendThread = new SendThread(); // Have thread properties and separate members

myRcvThread = new RcvThread(); // Have thread properties and separate members

Design Option #2 (Master):

Master thread -

Execute() 
{
    if (threadType == RCV_THREAD)
    {
        globalVar = new MasterThread(serialPortHandle);
    }
    while (!Terminated)
    {
        if (threadType == RCV_THREAD)
        {
            if(globalVar) 
            {  
                // do work
            }
        }
        if (threadType == SND_THREAD)
        {
            tCountSnd = GetTickCount() / SND_THREAD_DELAY;
            if (tCountSnd != tCountSnd2) {
               tCountSnd2 = tCountSnd;
               if (globalVar) {
                   // do sending work
               }
            }
        }
     }

}

+2  A: 

I've designed a thread for communicating on the serial port (in Python, not C++, but it doesn't matter much) as follows:

There's a single thread and two queues - one for sent and one for received messages. The thread always listens (asynchronously) on both the serial port (for received data) and the sending queue (to send stuff the application asks to send).

  1. If data arrived on the serial port, it's placed in the receive queue for the application's use
  2. If the application placed data into the send queue, the thread sends it down the serial port

This design makes more sense to me because the single resource (the serial port) is held by a single thread, and not shared by two. Breaking it to several classes sounds like an overkill to me, since reading/writing from queues and reading/writing from the serial port is a trivial operation (naturally the serial port is wrapped in a convenient class - by the way I really recommend this class by Ramon De Klein)

Oh, and it works very well.

Eli Bendersky
is the receive queue a global queue shared between the application and the Process/Sending Thread?
0A0D
It's a synchronized Queue object - this really depends on the threading/synchronization library you use in C++
Eli Bendersky
how do you prevent the receiving from being blocked if it is processing messages or is this queue handed off to a worker thread?
0A0D
@Roboto, I don't fully understand your question. Assume a non-blocking interface to the Queue (i.e. you can ask it whether it has something, and it won't block for this request).
Eli Bendersky
I mean to the serial port... you gather up the messages and then have to do something with it. Putting it in the queue is great but who processes the message - a separate thread? You wouldn't want to stop reading to process a message I would think
0A0D
I assume that the "application" does the processing. It runs the thread to read/write to the serial port, and processes what's received into the queue whenever it needs to - perhaps on some timer, or something like that. Completely application dependent.
Eli Bendersky
@Eli: I basically did what you did except the received messages are not queued, they are buffered into an `unsigned char` array and the commands to be sent are queued then later "consumed" by the same thread.. I have two main functions, checkport and checkcommands, in the same thread. Very fast and works great.
0A0D
+1  A: 

Regarding the queue to be shared .. wrap it in a separate class and implement the mutex handling there. Every thread class holds a reference to the queue wrapper and doesn't need to deal around with mutexes at all.

Alexander Gessler
+4  A: 

I think it's better to completely decouple the purpose or execution of a thread from the actual thread abstraction that you'll be using.

Make your thread class just a thin wrapper to allow you to start, stop, and join a thread. Have it take a functor object (or function pointer) in the constructor for the actual execution.

Or better yet, use one of the many available thread abstractions already out there instead of writing your own (boost::thread for one, but I bet whatever framework you're using already has a thread class).

Terry Mahaffey
+1 for Boost.Thread.
avakar
A: 

2nd choice is clearly a bad one. It is better to have 2 different classes , maybe you can have a base class which has common implementation. This is just an initial assessment please provide more information about your problem only then a good analysis of problem can be done

Yogesh Arora