Wefts::Thread Class Reference
[Thread object incapsulation]

#include <wefts_thread.h>

Inheritance diagram for Wefts::Thread:

Inheritance graph
[legend]
Collaboration diagram for Wefts::Thread:

Collaboration graph
[legend]
List of all members.

Detailed Description

Implements the abstraction of a thread.

A thread is an object that can be executed in a separate (parallel) environment.

The applications are required to overload the pure virtual method run(); that method should not be called directly, as the start() method will create a new thread and execute the run() function in parallel with the caller.

Note:
run() method can be called directly, if the application can be sure that the method is fully reentrant (does not use any global unguarded data). In fact, this is a common way to allow execution of a procedure in sequence or in parallel (or both) depending on external conditions or on user choice.
There are mainly two kind of threads: detached and non-detached. A detached thread is automatically destroyed as soon as it terminates, without further need of attention by the caller. A non-detached thread will not clean its data upon termination or cancellation. A caller may inspect the non-detached threads after their termination, while it's unsafe to reference detached therads after the detach() method call: they could terminate in any moment and their internal data may be destroyed without any furhter notification; access detached threads only if it can be demostrated that they can't be terminated in the meanwhile.
Note:
Corollary: Never detach threads created as static variables private for functions: the destructor may be called twice, once at thread termination and once at function stack unwinding, causing page faults. If the stack unwinding happens first the thread is safely terminated, but avoid detach function-scope thread objects, as they are anyhow safely collected by the destructor (that does all the needed cleanup); so, detaching a thread that is allocated as local function data is pointless.
Non detached threads have also a synchronization method, join(), can be called by some thread in the application to 1) know when the thread is done and 2) free OS specific data needed for parallel execution (join() won't free internal class data, that must be deleted manually).

If a thread becomes detached during another thread's join(), a NotJoinableError is immediately sent to the joining one.

A Wefts++ thread can be created detached or can be detached at any moment in its run() function with the detach() method. Use this method if you know that no other thread is going to join a running thread.

Note:
This differs from posix implementation of threads. A detached posix thread can't be joined (doing it would immediately return with error).
Wefts threads also implement deferred and kind cancellation. The thread can be created in cancellable and uncancellable mode. In cancellable mode, the thread can be interrupted and terminated in functions that are waiting for an external event to happen by the stop() method; this include input output functions and wait ( e.g. Wefts::Sleep() ) routines. In non-cancellable mode, the thread won't receive such uncontrollable cancel orders, but the member variable m_stopped will be set to true if thread is requested to terminate. The thread can then check periodically a variable and honor the request, if it wills, immediately or at any later moment. This is called a "kind" cancellation request, as the "final" word upon termination or is left to the application level code.

In both modes, the testCancel() protected member honors cancellation requests immediately, if they have been issued, immediately terminating the thread (and eventually destroying it if it is detached). As it is a protected member, it can be called only by the subclasses, and only if the thread that is calling the test is the one for which run() method has been called on the Thread object.

The thread can also switch to cancellable or uncancellable mode after its creation. The run() method is guaranteed not being interrupted before its execution begins, so it is possible to call the setCancel() protected member to override any default the start() method may have bestowed upon the thread. setCancel() method can also be called later on to "mark" critical sections where, although having access to blocking resources, the thread wish not to be interrupted.

Things NOT TO DO:

There isn't any control over programs misbehaving in this way, so the programmers must take care never doing something like this; anyway, the Cleanup Sequence system provides a good support to automatize this aspect (Cancellation Issues).


Public Member Functions

 Thread (OSPriority prio=PrioNormal, int boost=0)
 Fills member variables with default values.

virtual ~Thread ()
 Thread virutal destructor.

bool start (bool detachable=false, bool cancellable=true)
 Start asynchronous execution of the run() method.

bool stop ()
 Issue a stop request on the thread.

void detach ()
 Set this thread as "detached".

bool detached ()
 Returns true if thread is in detached state.

virtual void * join () throw ( NotJoinableError )
 Joins a thread, waiting for its termination.

bool running ()
 Returns true if thread is currently operating.

OSThreadgetThread ()
 Returns the OS specific thread id associated with this thread object.

void setData (void *data)
 Set optional specific thread data.

int sequence () const
 Returns the sequence count of this thread.

virtual void cleanup ()
 Termination hook called by the thread termination process.

bool pushCleanup (CleanupHandler *handler, int value=0)
 Adds a cleanup handler at thread termination.

bool popCleanup (bool execute=false)
 Removes latest registered cleanup handler.

bool popCleanup (CleanupHandler *handler, bool execute=false)
 Removes exacly the given cleanup handler, even if it's not the last pushed one.

bool priority (OSPriority prio, int boost=0)
 Changes the priority scheduling and boost of this thread.

virtual void * run ()=0
 Main thread function.

void * getRunReturn ()
 Returns run return code, if run has completed and returned.


Protected Member Functions

void testCancel ()
 Tests if a stop request has been issued, and if so, terminates the thread.

void setCancel (bool cando)
 Sets the cancellable thread mode.

void doDetach ()
 Phisically detaches this thread, removing all unneeded data.


Protected Attributes

OSThread m_thread
 Machine/os thread identificator for this object.

bool m_canCancel
 True if deferred cancellation is turned on.

void * m_thread_data
 Optional thread specific data that can be used by this object.

bool m_detached
 True if thread is detached.

bool m_stopped
 True if the thread has been stopped at low level (exit pending).

bool m_wasCanceled
 True if the thread received a stop() request while cancellation is disabled.

volatile bool m_running
 True if thread if running.

int m_thSequence
 This is the count of threads previously started plus two.


Private Member Functions

virtual void executionEnd ()
 Minimal thraed termination routines.

void setCancel ()
 Used internally to communicate the low-level threading system what cancellation mode is used.


Private Attributes

CleanupList m_cleanupHandlers
 Stack of cleanup handlers to call at termination.

OSPriority m_reqPriority
 Requested scheduling policy.

int m_reqBoost
 Requested priority boost.

Mutex m_guard
 Internal mutex used to protect concurrent access to internal variables.

void * m_runReturn
 Used by the C cleanup routine to set the return value on need.


Friends

void s_ThreadCleanupper (void *)
 Function used (internally) to invoke thread->cleanup() in case of cancellation.

void * s_ThreadRunner (void *)
void * s_ThreadRunFunc (void *)
 Function used (internally) to invoke thread->run().


Constructor & Destructor Documentation

Wefts::Thread::Thread OSPriority  prio = PrioNormal,
int  boost = 0
 

Fills member variables with default values.

Note:
IMPORTANT: Never, NEVER create threads as static items.
Thread items must always be dynamically allocated, or the cleanup system will be fooled. The thread object must stay alive for the whole life of the system thread, and static allocation would not grant this capability; other than that, the system needs to know what is going on in a thread object.

To automatically deallocate the thread item on termination, use start( true ); this makes the thread "detached", that will destroy the pointer to the thread object created by the constructor.

If there is the need to access the thread after is termination, join it and work on the thread pointer; then delete it. Deleting a thread object after that the thread routine is terminated is safe.

Long story short: thread objects are meant to be created only via the new constructor, or equivalent dynamic memory allocation method.

The caller can set a default scheduling policy, and eventually a default priority boost, that will be enacted on the thread as soon as it is created.

There may be some delay between the creation of the thread and the schedule policy change.

Parameters:
prio Scheduling policy (priority) for thread at start() request.
boost Scheduling priority boost.
See also:
OSThreadBase::priority() for details on schedule and priority handling.

Wefts::Thread::~Thread  )  [virtual]
 

Thread virutal destructor.

The destructor is meant to clean thread data after that thre thread has terminated. This implies that calling it while the thread is or may be still running (or at least, may be still engaged in its run() method) is generally a very bad idea.

Anyhow, mimimal actions are taken to provide a protection against total disaster in the most common case. In particular, if the deleted thread is not the current running one, the thread is stopped and joined. This means that if the target thread is unstoppable you may have to wait long, and if it is deadlocked, the thread calling the destructor will be deadlocked too. If the calling thread is the one that is currently under execution, the thread is automatically detached, so right after the destructor does its business, system resources are automatically freed.

If you know what you are doing, explicitly destroying a thread heap allocated variable is a shortcut for:

MyThread *th = new MyThread(); th->start(); delete th; // == th->stop(); th->join(); delete th;

and as join(), it can rise a NotJoinableError in case the thread becomes not joinable in the meanwhile; a detached thread has no safe way to be told by the destructor that it's going to be destroyed externally; it may ignore any stop() request and call its own destructor. For this reason, an assertion is failed (and the program aborts) if the thread is or becomes detachable during the destructor join().

Notice also that if the run() method returned a meaningful value, delete operator won't clean it, and a memory leak will be generated. In general, the correct and fault free sequence to cleanly delete a thread is:

MyReturnValue *ret = static_cast<MyReturnValue *>( th->join() ); // Ansi C++ allows delete on null objects (delete internally verifies object to be != 0). delete ret; delete th;

You can avoid the try/catch block if the target thread is not detachable.

It is absolutely safe (and will not lead to error throws) to call the destructor on a terminated thread.

Note:
It is important that detachable thread subclass overload this destructor (with another virtual destructor!) to provide automatic cancellation schemes.


Member Function Documentation

void Wefts::Thread::cleanup  )  [virtual]
 

Termination hook called by the thread termination process.

This method is called just before the thread terminates, and if the thread is detached, also just before thread destructor. This gives a chance to this thread to provide cleanup actions (as freeing mutexes not previously releases, close files and connections, logging the imminent termination, signaling in member variables things that an eventual join()er should know etc.).

The Thread class implementation of cleanup() calls all the cleanup functions, so a subthread is advised to call Thread::cleanup(), at least if it can check that there are pending cleanup handlers, or suspects it.

A subclass may also declare itself derived from both Thread and CleanupHandler, and then use pushCleanupHandler( this ) to subscribe itself to the thread object, instead of overloading this method; overloading is more efficient, but this latter strategy may be useful if the thread knows that many other cleanup handlers will be called randomly, and that its cleanup code must be queued in proper order.

Todo:
tests about stability of cleanup in stress environment (pushing handlers from other threads. Has it any sense?).
See also:
Cleanup system

void Wefts::Thread::detach  )  [inline]
 

Set this thread as "detached".

Set the thread type to detached: at thread termination, the object encapsulating this thread will be deleted (as well as OS resources needed to run this thread). This choice is not reversible; once a thread is detached, it can't be set to non-detachable state.

A joining thread waiting for this thread to terminate will immediately receive a NotJoinableError.

See also:
join()

bool Wefts::Thread::detached  )  [inline]
 

Returns true if thread is in detached state.

void Wefts::Thread::doDetach  )  [inline, protected]
 

Phisically detaches this thread, removing all unneeded data.

The detach() method only singals that this thread will not be joined by anyone, so (future) joiners are advised and the cleanup routine knows how to handle this thread. The job of signaling to OS that this thread is to be destroyed upon termination is done by this method. This is usually called by the automatic cleanup routine, but if there is some reason by which you want to terminate cleanly the thread with an early m_thread.exit(), you can use this doDetach() to prevent memory leaks.

void* Wefts::Thread::getRunReturn  )  [inline]
 

Returns run return code, if run has completed and returned.

If this not happened, 0 is returned.

OSThread* Wefts::Thread::getThread  )  [inline]
 

Returns the OS specific thread id associated with this thread object.

void * Wefts::Thread::join  )  throw ( NotJoinableError ) [virtual]
 

Joins a thread, waiting for its termination.

This method makes the caller to wait for this thread to be terminated. It can return in three cases:

  1. this thread cleanly terminates; in this case join() returns the void * returned by run() (that may be 0).
  2. this thread is detached; in this case join throws an NotJoinableError as soon as it is resumed after the joined thread has detached.
  3. the calling thread trying to join itself; also in this case, join() throws the NotJoinableError.
  4. the thread is not currently running.

If a join() trows a NotJoinableError, the caller should never use anymore the called object: in fact, a detached thread is destroyed before join can return, and using it would cause an immediate crash, while if the calling thread is awaken by a signal, there is no safe way to know if the joined thread will still be valid when the joiner tries to handle it.

Note:
Having join() to throw an exception can rightfully be considered a programming error that must be detected and fixed before program can be considered stable. For this reason, and for efficiency stake, in the future this may be turned into an assertion that terminates the program on join failure.
Returns:
the void* returned from thread's run() method (may be 0).
Exceptions:
NotJoinableError if the target thread cannot be joined (this is not a sytem error, but a programming error).
See also:
~Thread()

Reimplemented in Wefts::MoaningThread.

bool Wefts::Thread::popCleanup CleanupHandler handler,
bool  execute = false
 

Removes exacly the given cleanup handler, even if it's not the last pushed one.

Of course, the cleanup handler removed is the first one of the same kind of the pushed one; this is used to avoid mixing cleanup handlers from different classes that may interleave in cleanup calls.

Returns:
false if there aren't handlers to remove
See also:
CleanupHandler

bool Wefts::Thread::popCleanup bool  execute = false  ) 
 

Removes latest registered cleanup handler.

If execute is set to true, the cleanup code will be executed immediately.

Note:
Cleanup sequence is Experimental; it works, but there is the need to expermient more on the race conditions and how/where use mutexes to make it fast but not unsafe. Don't use it except for experimental code.
Returns:
false if there aren't handlers to remove
See also:
CleanupHandler

bool Wefts::Thread::priority OSPriority  prio,
int  boost = 0
 

Changes the priority scheduling and boost of this thread.

See also:
OSThreadBase::priority() for details on priority management.
Parameters:
prio Scheduling policy.
boost priority boost.
Returns:
true on success, false on failure.

bool Wefts::Thread::pushCleanup CleanupHandler handler,
int  value = 0
[inline]
 

Adds a cleanup handler at thread termination.

This method will return true unless the thread has been requested to stop, or it is already engaged in the cleanup process.

Cleanup handlers are executed in a LIFO order (they are stacked and the last one arrive is the first that will be called).

Note:
Cleanup sequence is Experimental; it works, but there is the need to expermient more on the race conditions and how/where use mutexes to make it fast but not unsafe. Don't use it except for experimental code.
See also:
CleanupHandler

virtual void* Wefts::Thread::run  )  [pure virtual]
 

Main thread function.

This pure virtual method must be overloaded by subclasses to implement the thread main rountine. This is executed after that start() method launches the new thread. It is possible to call run() directly i.e. when your class may run both in parallel ( run() is called indirectly by start() ) and sequence ( run() is called directly by the caller ).

The return value is available to communicate directly with a thread evetnaully joining this one: the returned void pointer will be passed as return of the other thread join() method. Joining a detached thread will always result in a void return, regardless of what run() method returned.

Also, if the thread is not detached, after its termination the return value of this method is available by calling getRunReturn().

Note:
Never return a dynamically allocated object in run() when the thread is detached; this would result in memory leaks, unless the returned object is anyway destroyed by the class destructor. Return code should be something like:
... if ( detached() ) return 0; else return myCuteObject; ...
Anyway, object oriented implementation offers more elegant solutions, as providing a member variable (eventually guarded with accessors) to the joining thread.

So, unless you have special reasons, run() method should always return 0.

bool Wefts::Thread::running  )  [inline]
 

Returns true if thread is currently operating.

There may be a little time in which the thread is reported to be running, but the run() method is still not executed, and another in which the thread is reported not to be running, but the OS level thread is still not terminated. Anyway, this problem can be safely ignored, as in the first case, nothing is going to stop the thread from run as soon as possible, and the OS resource for the thread are ready to go, while in the latter case the Wefts thread is not operating anymore and the OS level thread will be terminated as soon as possible. (It is under all aspects a "dead thread walking" :-)

int Wefts::Thread::sequence  )  const [inline]
 

Returns the sequence count of this thread.

Used for reference and debugging purposes. The main thread has a "vritual" sequence of 1; the threads started with start() method have a number ranging from 2 to MAXINT. Notice that this sequence count is invalid if thread has not been started yet (i.e. if you are running the run() method sequentially.

See also:
m_thSequence

void Wefts::Thread::setCancel bool  cando  )  [protected]
 

Sets the cancellable thread mode.

If the parameter is ture, the thread can be canceled at wait or blocking points, as waits for OS calls to return or in Wefts::Sleep() calls. If set false, only an explicit testCancel() call, or a hand-made check on the m_stopped member variable will terminate the thread upon request.

Parameters:
cando true if thread is cancellable, false otherwise.

void Wefts::Thread::setCancel  )  [inline, private]
 

Used internally to communicate the low-level threading system what cancellation mode is used.

void Wefts::Thread::setData void *  data  )  [inline]
 

Set optional specific thread data.

bool Wefts::Thread::start bool  detachable = false,
bool  cancellable = true
 

Start asynchronous execution of the run() method.

The execution of the run method is started as soon as possible, but both the m_thid and m_thSequence members are immediately set; also the count of active threads is updated immediately.

Parameters:
detachable true if thread is detached, false otherwise
cancellable true if thread is cancellable, false otherwise
Returns:
true if thread can be started, false on error

bool Wefts::Thread::stop  ) 
 

Issue a stop request on the thread.

The thread will honor the request depeding on its current cancellable policy and on its own decision. Is thus important designing threads so that they never enter endless loops or deadlocks so that they can't check for stop requests being issued.

Stop() method will stop the thread, privided it's running. If the cancellation is currently disabled the stop request will be cached; in the case cancellation is re-enabled, the stop request is re-iterated. Note that this does not makes setCancel() a cancellation point; reiterating at low level the stop request will not cause termination of the thread until a cancellation point is met. Simply, if setCancel() is disabled, stop() won't do nothing except (atomically) recording the fact that it has been called; this fact will become meaningful only in the event of cancellation being enabled in a second moment.

See also:
setCancel()
Returns:
false if the stop request can be honored, false if it can't be honored currently due to setCancel() policy or running status.

void Wefts::Thread::testCancel  )  [inline, protected]
 

Tests if a stop request has been issued, and if so, terminates the thread.

This method works the same both if the thread is cancellable or not. Indeed, if the thread is not cancellable, this is the best way to honor eventual cancellation requets issued in the meanwhile. Also, this can be useful in testing for cancellation requests issued while the thread is engaged in long computations.


Friends And Related Function Documentation

void s_ThreadCleanupper void *  param  )  [friend]
 

Function used (internally) to invoke thread->cleanup() in case of cancellation.

As this function is the only one that has the right to delete the thread object in case of detached thread, this function is also responsible to set the m_runReturn parameter in case the thread is NOT detached. For this reasion, this function is fed with a ThreadAndReturn pointer as parameter.

Parameters:
param a ThreadAndReturn structure pointer, containing the thread object and the run return value, if the run function had the chance to return, or 0 otherwise.

void* s_ThreadRunFunc void *  param  )  [friend]
 

Function used (internally) to invoke thread->run().

void* s_ThreadRunner void *  data  )  [friend]
 


Member Data Documentation

bool Wefts::Thread::m_canCancel [protected]
 

True if deferred cancellation is turned on.

CleanupList Wefts::Thread::m_cleanupHandlers [private]
 

Stack of cleanup handlers to call at termination.

bool Wefts::Thread::m_detached [protected]
 

True if thread is detached.

Mutex Wefts::Thread::m_guard [private]
 

Internal mutex used to protect concurrent access to internal variables.

int Wefts::Thread::m_reqBoost [private]
 

Requested priority boost.

OSPriority Wefts::Thread::m_reqPriority [private]
 

Requested scheduling policy.

volatile bool Wefts::Thread::m_running [protected]
 

True if thread if running.

See also:
running()

void* Wefts::Thread::m_runReturn [private]
 

Used by the C cleanup routine to set the return value on need.

bool Wefts::Thread::m_stopped [protected]
 

True if the thread has been stopped at low level (exit pending).

OSThread Wefts::Thread::m_thread [protected]
 

Machine/os thread identificator for this object.

void* Wefts::Thread::m_thread_data [protected]
 

Optional thread specific data that can be used by this object.

int Wefts::Thread::m_thSequence [protected]
 

This is the count of threads previously started plus two.

See also:
sequence()

bool Wefts::Thread::m_wasCanceled [protected]
 

True if the thread received a stop() request while cancellation is disabled.


The documentation for this class was generated from the following files:
Generated on Tue Oct 5 14:57:03 2004 for Wefts by doxygen 1.3.7