Message types are defined by the application. Each type must be represented by a positive integer. Message type zero is reserved to denote the absence of a message. Message type -1 (cast to a Ct_msgtype) is reserved to denote a timeout.
The thread handle must have been obtained from a successful call to ct_create_thread(), ct_create_sleeping_thread(), or ct_self(). If the thread handle is invalid because the thread has expired, the message will be silently discarded. If the thread handle is invalid for any other reason, the results are undefined.
Optionally, the sender may include arbitrary data with the message by supplying a non-null pointer to the data, together with a non-zero length (for Embedded Cheap Threads this length must not exceed a maximum fixed at compile time). The ct_send_msg() function makes a copy of the data to be delivered later to the recipient. The format of the data is defined by the application. For example, it may contain text, binary fields, pointers, or a mixture of data types.
Short message data will be packaged along with the rest of the message. For data longer than CT_MSG_BUF_LEN bytes (defined in ct.h as 16), ct_send_msg() will dynamically allocate memory as needed and deliver a pointer to that memory. For performance reasons, then, it pays to keep your messages short.
To address this problem, the ct_distribute_msg() function sends a copy of a message to all the threads that have previously subscribed to messages of that type. The parameters are similar to those of the ct_send_msg() function, except that you don't have to supply a thread handle.
A thread may subscribe to a given message type by calling the ct_subscribe() function. It may be subscribed to more than one message type at the same time. It may cancel a subscription by calling ct_unsubscribe(), or cancel all subscriptions by calling ct_unsubscribe_all().
If a thread is still subscribed to any message types when it expires, Cheap Thread will automatically cancel all the subscriptions.
Broadcasting a message is like distributing a message type to which all threads have subscribed. It is slightly more efficient, however, because it avoids the overhead involved in keeping track of subscriptions.
When the thread returns control to the scheduler, the scheduler dispatches all the events in the global queue. For message events, the scheduler delivers to each recipient a pointer to a shared copy of the message (this copy is deallocated when the last recipient discards it). Finally, the scheduler enqueues each recipient for execution at the highest priority.
There is one exception. If the recipient is already enqueued because of a previous event, the scheduler leaves it where it is in the run queue. Otherwise a succession of events might move the thread repeatedly to the end of the queue, never giving it a chance to run. This exception will make more sense once you have read about the internals of the scheduler.
Note that ct_query_msg() does not remove anything from the message queue. It is up to the thread to call either of the following functions:
If there are multiple messages in a thread's input queue, the thread will receive them in the sequence in which they were sent. If a thread returns without removing all of its messages from the input queue, it will be enqueued for execution again at the highest priority, even if it has called ct_wait() to put itself to sleep. As a result, in most cases the thread doesn't need to loop explicitly through its input messages. It can process one message at a time, and let the scheduler handle the looping.
If any messages remain in its input queue when a thread expires, Cheap Threads will automatically destroy them.
This is one of the few guarantees that Cheap Threads can make about the timing of threads, and it may be useful in some cases.
For example, instead of sending a long message, a thread might send a pointer to the message data. Next time the sender runs, it knows that each recipient has received the message, so it can deallocate or overwrite the original. This approach may use less memory and less CPU time than sending a copy of the full message.