The Channel Primitive

ThreadMentor supports synchronous and asynchronous one-to-one channels. This means a channel can be built and used by two threads to which this channel connects. Hence, we need to find someway for each thread to identify itself so that they can be used for channel construction. This is the concept of user-defined ID.

User Defined ID

Each thread can be assigned with a non-negative integer identifier; however, these identifiers must be unique. Then, you must instruct the thread system to save this user-defined ID for later use. This is easy to do. Suppose 10 is the user-defined ID for a thread. Then, put the following in the constructor of that thread:

 
UserDefinedThreadID = 10;
In the above, UserDefinedThreadID is a variable declared in the Thread class. After this, you can use either 10 or the value stored in UserDefinedThreadID to identify this thread.

Declaring Channels

To declare a synchronous (resp., asynchronous) channel, use class SynOneToOneChannel (resp., AsynOneToOneChannel). The constructor of a channel class requires three arguments: the name of the channel and the user defined IDs of the threads to which this channel connects. Once a channel is built between two threads, only these threads can send messages to and receive messages from this channel. The following builds a synchronous channel, with name "Channel15-03", between thread 15 and 3. Note that 15 and 3 are user defined thread IDs:

 
SynOneToOneChannel  channel("Channel15-03", 15, 3);
In some situations where a pointer to a channel is more appropriate, we can also use the following way:
 
SynOneToOneChannel  *channel;

channel = new SynOneToOneChannel("Channel15-03", 15, 3);

Sending and Receiving Messages

Classes SynOneToOneChannel and AsynOneToOneChannel have two methods Send() and Receive() for sending messages into and receiving messages from the channel. Two arguments are required for both methods. The first argument is a pointer to an area that contains the message to be sent or the area that will be used to store the received message. The second argument is the size of the message. For example, if we intend to send an integer value stored in variable Msg into the channel declared above, we should use one of the following forms, depending on the way the channel channel is declared.

 
channel.Send(&Msg, sizeof(int));

channel->Send(&Msg, sizeof(int));
Here, &Msg is the pointer to the area that contains the message and sizeof(int) computes the size of an integer.

Now, suppose we wish to receive a message in an array of four integers from channel Chan. Then, we should do the following:

 
int  Msg[4];

Chan.Receive(Msg, 4*sizeof(int));

Chan->Receive(Msg, 4*sizeof(int));
In fact, you can use any data structure for a message that may contain different data types. The following example shows the use of a data structure that contains a double, a int, and a char array of 100 entries:
struct Data {
     double  x;
     int     y;
     char    z[100];
} Msg;


Example.Send(&Msg, sizeof(Data));

Example.Receive(&Msg, sizeof(Data));
There is a pitfall when using messages that are not of primary types (e.g., int, char, float and double). Because the visualization system does not know the format or structure of a message, it may not be able to display the message content properly.