MessageLoop_t Class Reference

Message loop class. More...

#include <UTMessageLoop.h>

Inheritance diagram for MessageLoop_t:
Thread_t BTreeNode_t< MessageLoop_t, MessageLoop_t * > LinkedListNode_t< Thread_t > App_t IdleMessageLoop_t

List of all members.

Public Member Functions

 MessageLoop_t (thread_priority_t priority=eTHREADPRI_normal, bool support_timeout=false, int32 timeout_ms=-1)
virtual ~MessageLoop_t ()
virtual void SetTimeout (int32 timeout_ms)
int32 Token () const
virtual void Start (int32 stack_size=0)
void AddTask (Task_t *task)
void RemoveTask (Task_t *task)
void RequestQuit (const MessageDestination_t< QuitResponseMessage_t > &respond_to)
void RequestQuit ()
virtual void WaitForThreadToExit ()
virtual void QuitRequested ()
virtual bool IsQuitInProgress ()
virtual void CancelQuit ()

Protected Member Functions

virtual void Main ()
virtual void Timeout ()
virtual void SetMessageAvailEvent ()

Detailed Description

Message loop class, which in conjunction with Task_t, Message_t, MessageReceiver_t, and MessageDestination_t, implements a messaging architecture. A message loop always runs in its own thread, which can be the main application thread if it was registered as such using Thread_t::RegisterMainThread.

Messages are sent to Task_t subclasses, which are installed into their parent message loop. Tasks can only be added or removed either before the message loop is started, or from the message loop's own thread context.

Tasks receive messages by way of dedicated receiver functions. This avoids the classic design problem of messaging systems where the message loop's dispatch mechanism consists of a switch on the message type. The author has found that the temptation to handle messages directly in the switch is far too great, and those switches ultimately turn out to be massive, unwieldy, inefficient beasts. Forcing the point at the architectural level that every message must have a dedicated handler function forces better design.

Because a task can have multiple receiver functions for various messages, each receiver function is itself represented by a MessageReceiver_t member which serves both for routing messages to their final destinations and for runtime type checking when a message is coming out of a message queue and needs to be cast to the message type expected by the receiver function. A task always contains receiver functions and message receiver objects in pairs. See the Task_t documentation for an example.

The last class involved in the messaging architecture is MessageDestination_t. A message destination represents a destination to which a message can be sent. This is important because messages are often sent to destinations which are running in a different thread than the sender. This object is thread safe in that if the destination is deleted before the message source has been informed about the destination having been deleted, any messages will be properly disposed of. Messages are sent using the MessageDestination_t class's SendMessage or SendMessageAsync function. When SendMessage is called from the same thread in which the destination is running, a call is made directly into the receiver function with all the efficiency of a callback. If the action taken in the receiver function is dangerous, for example deleting a task, the SendMessageAsync function should be used. That way, the receiver function will be guaranteed to be called from what is effectively the root of the call stack, avoiding the danger of deleting a task which is still being used somewhere up the call stack.

Definition at line 44 of file UTMessageLoop.h.


Constructor & Destructor Documentation

MessageLoop_t::MessageLoop_t ( thread_priority_t  priority = eTHREADPRI_normal,
bool  support_timeout = false,
int32  timeout_ms = -1 
)

Message loop constructor. Another thread must call Start to begin the message loop execution unless this is the main application thread, having been registered using Thread_t::RegisterMainThread, in which case Its Main function should be called directly. If support_timeout is true, the message loop will, if a message does not arrive in the timeout period, call the Timeout function which should be overridden by the derived class. In that case, the timeout period in milliseconds is intially set to timeout_ms. The timeout period can be changed using the SetTimeout function, which can be called before the message loop has started, or if it has started, in the message loop thread. If the message loop has already started and SetTimeout is called, it will not take effect until the next timeout period based on the old timeout has expired in the thread, and doing do is not particularly useful or recommended. Other than -1 (no timeout), the timeout, if specified, must be greater than or equal to 50 milliseconds to avoid burning an excessive amount of CPU time.

virtual MessageLoop_t::~MessageLoop_t (  )  [virtual]

Message loop destructor. Unless the message loop has been registered as being the main thread, WaitForThreadToExit must be called first. Before that can be done, RequestQuit must have been called. Any tasks or multi-waitable objects which have not yet been removed will be removed from the message loop destructor.


Member Function Documentation

virtual void MessageLoop_t::SetTimeout ( int32  timeout_ms  )  [virtual]

Sets the timeout period after which, if no message has arrived, the Timeout function will be called. This function can be called before or after the message loop has started, including from in or outside of the message loop thread. Other than -1 (no timeout), the timeout, if specified, must be greater than or equal to 50 milliseconds to avoid burning an excessive amount of CPU time.

Reimplemented in App_t.

int32 MessageLoop_t::Token (  )  const [inline]

Returns the token which, together with the "this" pointer uniquely identifies the message loop.

Definition at line 309 of file UTMessageLoop.h.

virtual void MessageLoop_t::Start ( int32  stack_size = 0  )  [virtual]

Creates a thread and starts the message loop, which in its own thread, will run inside of Main. If the message loop has been registered as the main thread using Thread_t::RegisterMainThread, Start will call Main directly and and not return until Main does. If the stack size is 0, an appropriate default is used.

Under Windows, use of eTHREADPRI_time_critical or above can interfere with serial port driver function. The serial port driver will then be running at an equal or lower priority and unable to service the UART FIFO in a timely manner, resulting in FIFO overflows.

Reimplemented from Thread_t.

Reimplemented in App_t.

void MessageLoop_t::AddTask ( Task_t task  ) 

Adds a task to the message loop. Tasks are aggregates of message receivers. As an example of what a task could be, it could implement a state machine with message receivers for each of the various inputs which drive the state machine progression.

void MessageLoop_t::RemoveTask ( Task_t task  ) 

Removes a task from the message loop.

void MessageLoop_t::RequestQuit ( const MessageDestination_t< QuitResponseMessage_t > &  respond_to  ) 

Queues an asynchronous quit request to the message loop. In the message loop thread, all tasks will be requested to quit. If no tasks block quitting by responding with eQUIT_denied or eQUIT_deferred, the message loop will stop running and it will be safe to call WaitForThreadToExit then delete it. Once the message loop has confirmed that it will quit, WaitForThreadToExit must be called before the message loop can be deleted. If it is known by design that the message loop will always quit when requested, no respond_to destination is needed and the caller can use the no-response form of RequestQuit then follow up directly with a call to WaitForThreadToExit then delete the message loop.

void MessageLoop_t::RequestQuit (  ) 

Queues an asynchronous quit request to the message loop. In the message loop thread, all tasks will be requested to quit. If no tasks block quitting by responding with eQUIT_denied or eQUIT_deferred, the message loop will stop running. It is safe to call WaitForThreadToExit then delete it, but the design should ensure that the message loop will always quit. If that is not the case, then the responding form should be used.

virtual void MessageLoop_t::WaitForThreadToExit (  )  [virtual]

Called from another thread, waits for the message loop to exit. RequestQuit must have been called first, and the message loop must have confirmed that it will be quitting if a respond_to destination was provided.

Reimplemented from Thread_t.

virtual void MessageLoop_t::QuitRequested (  )  [virtual]

Called when a quit request has been received. The default implementation calls QuitRequested in all tasks. If any task responds with eQUIT_denied, the message loop will not quit. If any task responds with eQUIT_deferred, the task is considering whether to quit and a response will be provided later.

Derived classes must always call MessageLoop_t::QuitRequested in order to actually make the message loop quit. This would be done after all derived class considerations have determined that it is now time to quit. Derived class considerations would be things like requesting all windows to quit before other types of tasks receive the same request.

Reimplemented in App_t.

virtual bool MessageLoop_t::IsQuitInProgress (  )  [virtual]

Indicates whether MessageLoop_t::QuitRequested has been called has been called and is still running, or with a quit decision having been deferred. Derived classes may override this function to indicate that quit is in progress even if MessageLoop_t::QuitRequested has not been called. In that case, the derived class's quit state machine must call MessageLoop_t::QuitRequested eventually when the derived class decides it is time to quit.

Reimplemented in App_t.

virtual void MessageLoop_t::CancelQuit (  )  [virtual]

Cancels any quit request which may be in progress.

Reimplemented in App_t.

virtual void MessageLoop_t::Main (  )  [protected, virtual]

Message loop thread entry point. Another thread must call Start to begin the message loop execution. If this message loop runs in the main thread (having been registered using Thread_t::RegisterMainThread), Start will call Main directly and not return until Main does.

Implements Thread_t.

Reimplemented in App_t.

virtual void MessageLoop_t::Timeout (  )  [protected, virtual]

If the message loop is constructed to support timeouts, a timeout other than -1 has been specified, and a timeout does occur, this function is called.

virtual void MessageLoop_t::SetMessageAvailEvent (  )  [protected, virtual]

Notifies the message loop that a message has been queued.

Reimplemented in App_t.


The documentation for this class was generated from the following file:

Generated on Tue Dec 14 22:35:07 2010 for UT library by  doxygen 1.6.1