1. System Configuration - Header files & Compiler Directives

2. Thread Object

The PiThreads thread object provides a user with the ability to generate a thread of execution which can easily me managed through the public and protected member functions of the class Thread. This is done by providing the abstract base class thread. This class is defined within the file thread.h, which must be included after #defining POSIX or WIN.

The public and protected elements of the thread class through which a user can interface with the thread object can be seen below.

 


class Thread

public:

Thread();

virtual ~Thread();

bool Create ();

bool Create(unsigned long stack_size);

bool CreateSuspended();

bool CreateSuspended(unsigned long stack_size);

unsigned int GetID() const;

bool Execute();

void Resume();

void Suspend();

void Terminate();

bool SetPriority(priority_level b_prio);

char * GetPriority();

bool Join() const;

void SafePoint();

void Suspend_Thread();

void T_Sleep(unsigned long millisecs);

 

protected:

virtual void ThreadRoutine() = 0;

 

 


In order to instantiate a thread, a class is derived from the PiThreads class Thread, and provided the derived class the default constructor Thread( ). Then member function ThreadRoutine( ) is overridden with the implementation specific thread routine. A generic example of such a class can be seen below.

 


//#define WIN or POSIX

#include <threadcpp.h>

class ThreadDemo : public Thread

{

public:

 

ThreadDemo() : Thread() {}

void EntryRoutine(void)

{

SafePoint(); //Allow for thread suspension/termination

//Insert thread routine here

}

 

};

 

 

As declared above, the class ThreadDemo instantiates a thread with an empty thread entry routine and an empty thread exit routine. The member function SafePoint() which is inserted in the thread routine will be discussed shortly.

Now the derived class has been defined, it can be instantiated. PiThreads allows several methods to instantiate a thread. Create( ) instantiates a thread in running mode such that it begins execution of its thread routine immediately upon creation. CreateSuspended( ) initializes a thread in a suspended state that does not begin execution of its thread routine until a call to Execute( ) is issued. Both of these functions have overloaded partners with a parameter unsigned long stack_size. This parameter allows for the user to instantiate a thread with an associated stack size in bytes corresponding to the value passed to stack_size.

An example of all methods of instantiating a thread can be seen below.

 

#define WIN or POSIX

void main()

{

ThreadDemo Threads[4];

Threads[0].Create(); //Creates a thread in running mode with default stack size

Threads[1].Create(1048576); //Creates a thread in running mode with a stack

//size of 1MB

 

Threads[2].Construct(); //Creates a thread in suspended mode with a

// default stack size

Threads[3].Construct(1048576)//Creates a thread in suspended mode with a

// stack size of 1MB

 

Threads[2].Execute(); //Begin execution of Threads[2]

Threads[3].Execute(); //Begin execution of Threads[3]

 

 

for( int I = 0; I < 4; I++) //Wait for threads to complete their thread routine by

Threads[I].Join(); //joining threads to main thread

 

}

 


A OSI_Thread thread object can also have a priority level associated with it. PiThreads defines seven levels of thread priority, and stored in a variable of the defined type priority_level. The relative priority levels which can be assigned to an PiThreads thread object can be seen below in Table 2.

 

Table 2 PiThreads Thread Priority Levels

Type Name

Constant

priority_level

IDLE

 

LOWEST

 

BELOW_NORMAL

 

NORMAL

 

ABOVE_NORMAL

 

HIGHEST

 

TIME_CRITICAL

 

The desired priority level is then passed to the function SetPriority(priority_level priority) . As with all the functionality of the thread object, the member function can be called from either a reference to the class instance a la dot operator or can be called from within the overridden ThreadRoutine( ). An example of setting a thread objects priority can be seen below.

 

#define WIN

void main()

{

ThreadDemo A; //Declare thread instance

ThreadDemo B; //Declare thread instance

 

A.Construct(); //Create A in a suspended state

B.Construct(); //Create B in a suspended state

A.SetPriority(HIGHEST); //Set As priority to HIGHEST

B.SetPriority(LOWEST); //Set Bs priority to LOWEST

A.Execute(); //Begin executing thread A

B.Execute(); //Begin executing thread B

A.Join(); //Wait for thread A to complete execution

B.Join(); //Wait for thread B to complete execution

}

 

 


After assigning a priority, the thread instance can call GetPriority( ) to return the priority_level associated with the thread, or GetNativePriority( ) to determine the numeric representation of the threads priority on the respective platform.

As seen in all the examples thus far, a thread can exercise join functionality with a call to Join( ). When the Join( ) member function is called the calling thread is blocked until execution of the thread referenced by the join has terminated. If execution of the thread referenced by the join has already terminated, the calling thread is not blocked. In all the examples thus far, the instantiated thread is joined with the main thread at one point. When an instances Join( ) member function is called from the main thread, the main thread is blocked until that instance of a thread completes execution of its thread routine.

A thread object has the capability of being able to suspend and resume execution of a thread with the member functions Suspend() and Resume(). Also along these lines, a thread can be forcible terminated with a call to Terminate(). Suspend and terminate functionality is offered with the assistance of the member function SafePoint(). SafePoint() is to be inserted at various points throughout the thread routine if there are to be requests to suspend or terminate thread execution as expressed through the Suspend() and Terminate() member functions. SafePoint() must be inserted in places in the thread routine where all side effects are accounted for and thread preemption will cause no unspecified behavior. After a thread has been suspended, its execution can be resumed by calling Resume(). An example of thread suspension and termination can be seen below

 


//#define WIN or POSIX

class ThreadDemo : public Thread

{

public:

 

ThreadDemo() : Thread() {}

void EntryRoutine(void)

{

SafePoint(); //SafePoint at start

//Insert thread routine here

for(;;)

{

//thread routine

SafePoint(); //SafePoint() in loop

}

void ExitRoutine(void)

{

//Any clean-up can go here

}

};

 

void main()

{

ThreadDemo ThrA; //Declare thread object

ThreadDemo ThrB; //Declare thread object

ThrA.Create(); //Start executing thread routine

ThrB.Create(); //Start Executing thread routine

ThrA.Terminate(); //Forcibly terminate thread ThrA

ThrB.Suspend(); //Suspend execution of ThrB

ThrB.Resume(); //Resume execution of ThrB

ThrB.Join(); //Wait for ThrB to complete execution

}

 

 


Here in addition to the start of the thread routine, SafePoint() is inserted inside of a loop within the thread routine at a position where all side effects are accounted for. Then in main(), two thread instances are declared, ThrA and ThrB. ThrA and ThrB are then initialized in a running mode with a call to Create(). ThrA is then forcibly terminated with a call to its Terminate() member function. Execution of ThrB. Is then suspended and then resumed with subsequent calls to Suspend() and Resume().

Error handling in the PiThreads thread object allows for graceful termination of a thread which has encountered an error. The user can #define DEBUG, and the thread object will output the source of any error which it encounters. This functionality is provided to assist debugging of a multithreaded aapplication developed with PiThreads.