Main Page Class Hierarchy Compound List File List Compound Members File Members

# threadableobject.h

Go to the documentation of this file.

    00001 /*
    00002 ** ThreadableObject is a base class for objects that are intended to
    00003 **                  internally spawn processing threads to execute
    00004 **                  specific member methods....a common example would be
    00005 **                  a multi-threaded server.
    00006 **                  This is needed because C++ member functions do not
    00007 **                  have the signature required by thread-spawning
    00008 **                  library functions.
    00009 **
    00010 **
    00011 **   Derive the object class from ThreadableObject, and implement
    00012 **     the class's StartThreadFunc method (this is the method through
    00013 **     which a newly spawned thread reenters the class code).
    00014 **   At the locations in the new class where a handler thread is to be
    00015 **     spawned, set any appropriate variables (see discussion below),
    00016 **     then call StartThreadWithArg() or StartThread().
    00017 **
    00018 **   Any method to be executed by a spawned thread should generally
    00019 **     have the signature:  THR_RTR func(void *).  That is, it returns void
    00020 **     and takes one parameter that is a void pointer.  The parameter is
    00021 **     not strictly required, but it can simplify coding under one set
    00022 **     of circumstances.
    00023 **   The spawning process allows a single void pointer parameter to be
    00024 **     passed to a new thread.  Even if a method to be executed by a
    00025 **     spawned thread needs no parameters, the void pointer must still
    00026 **     be passed, even as NULL.  Keep in mind that
    00027 **   If there will be more than one function that might be executed by
    00028 **     a spawned thread, then there must be some way for a thread
    00029 **     to determine which method to enter.  One way to do this is
    00030 **     by using a member variable (possibly with a static mutex).
    00031 **     The method might also be indicated as part of a structure
    00032 **     passed to the spawning code through the void pointer parameter.
    00033 **   In some cases, the simplest routing code might result with an
    00034 **     implementation that uses a pointer to class member function:
    00035 **     <return_type>(<class_name>::*<pointer_type_name>)(<argument_list>)
    00036 **     All of the methods pointed to by this pointer type must have the
    00037 **     same signature.  If they all really need different parameters,
    00038 **     then designing them all to accept a single void pointer parameter
    00039 **     will make them look the same.  Using this method, just before calling
    00040 **     StartThreadWithArg, set the static method pointer to
    00041 **     point at the desired method:
    00042 **       <my_member_pointer> = &<class_name>::<method_name>
    00043 **     and in the StartThreadFunc, dereference the member pointer:
    00044 **       (this->*<my_member_pointer>)(p_arg)
    00045 **     note that in this call, p_arg is the void pointer passed through
    00046 **     the spawn process -- just that some of the methods might use it and
    00047 **     some might not.
    00048 **     The reason why this is a simplification is that the code in
    00049 **     the StartThreadFunc method does not have to decode the correct
    00050 **     method to call based upon the void pointer contents, or any
    00051 **     other variables -- it is implicit within the member method pointer.
    00052 **     So, this implementation would be appropriate if the logic for
    00053 **     determining which method a new thread should execute is complex.
    00054 */
    00055 //---------------------------------------------------------------------------
    00056 #ifndef threadableobjectH
    00057 #define threadableobjectH
    00058 //---------------------------------------------------------------------------
    00059 #include <worm_statuscode.h>
    00060 #include <mutex.h>
    00061
    00062
    00063 //---------------------------------------------------------------------------
    00064
    00065 #if defined(_WINNT) || defined(_Windows)  // - - - - - - - - - - - - - - - - - - - - - - -
    00066
    00067
    00068 #include <windows.h>
    00069 #include <process.h>
    00070
    00071 #include <stddef.h>
    00072
    00073 typedef unsigned int TO_STACK_SIZE;
    00074 typedef long         TO_THREAD_ID;
    00075
    00076
    00077 #define THREAD_RETURN void         //     Thread functions return this
    00078
    00079
    00080
    00081 #elif defined(_SOLARIS)  // - - - - - - - - - - - - - - - - - - - - - - -
    00082
    00083
    00084 #include <stdio.h>
    00085
    00086 #include <sys/types.h>
    00087 #include <thread.h>
    00088
    00089 typedef size_t       TO_STACK_SIZE;  // or is it unsigned int?
    00090 typedef thread_t     TO_THREAD_ID;
    00091
    00092
    00093 typedef void THREAD_RETURN;         //     Thread functions return this
    00094
    00095
    00096 #else                   // - - - - - - - - - - - - - - - - - - - - - - -
    00097
    00098 #error threadableobject.h not complete for this O/S
    00099
    00100 #endif  // - - - - - - - - - - - - - - - - - - - - - - -
    00101
    00102 //---------------------------------------------------------------------------
    00103
    00104
    00105
    00106 class ThreadableObject
    00107 {
    00108 protected:
    00109
    00110    /*
    00111    ** StartThreadWithArg() -- start a new thread with argument(s)
    00112    **
    00113    **  Arguments:
    00114    **     stack_size: Stack size of new thread in bytes
    00115    **                 If 0, stack size is set to 8192.
    00116    **                 In OS2, 4096 or 8192 is recommended.
    00117    **                 In SOLARIS, this argument is ignored
    00118    **                 In Windows NT, if stack_size=0, use the stack
    00119    **                 size of the calling thread.
    00120    **     thread_id:  Thread identification number returned to
    00121    **                 calling program.
    00122    **     arg:        an unsigned long (void*) passed to the thread.
    00123    **     p_isdaemon  start the thread/process as a daemon
    00124    **                 rather than internal thread (Solaris only)
    00125    **
    00126    **  Returns:
    00127    **     WORM_STAT_FAILURE if error
    00128    **     WORM_STAT_SUCCESS if ok
    00129    */
    00130
    00131    WORM_STATUS_CODE StartThreadWithArg( TO_STACK_SIZE   stack_size
    00132                                       , TO_THREAD_ID  * thread_id
    00133                                       , void *          arg
    00134 #ifdef _SOLARIS
    00135                                       , bool            p_isdaemon = false
    00136 #endif
    00137                                       );
    00138
    00139    /*
    00140    ** StartThread() -- start a new thread with no arguments
    00141    **
    00142    **  Arguments:
    00143    **     stack_size: Stack size of new thread in bytes
    00144    **                 If 0, stack size is set to 8192.
    00145    **                 In OS2, 4096 or 8192 is recommended.
    00146    **                 In SOLARIS, this argument is ignored
    00147    **                 In Windows NT, if stack_size=0, use the stack
    00148    **                 size of the calling thread.
    00149    **     thread_id:  Thread identification number returned to
    00150    **                 calling program.
    00151    **
    00152    **  Returns:
    00153    **     WORM_STAT_FAILURE if error
    00154    **     WORM_STAT_SUCCESS if ok
    00155    */
    00156
    00157    WORM_STATUS_CODE StartThread( TO_STACK_SIZE   stack_size
    00158                                , TO_THREAD_ID  * thread_id
    00159 #ifdef _SOLARIS
    00160                                , bool            p_isdaemon = false
    00161 #endif
    00162                                )
    00163    {
    00164       return StartThreadWithArg( stack_size
    00165                                , thread_id
    00166                                , NULL
    00167 #ifdef _SOLARIS
    00168                                , p_isdaemon
    00169 #endif
    00170                                );
    00171    }
    00172
    00173    /*
    00174    **  KillSelfThread() -- Exit thread without effecting
    00175    **                      other threads
    00176    */
    00177
    00178    static void KillSelfThread();
    00179
    00180    /*
    00181    **  WaitForThread() -- wait for thread to terminate
    00182    **
    00183    **  Returns:
    00184    **    WORM_STAT_FAILURE if error
    00185    **    WORM_STAT_SUCCESS if ok
    00186    */
    00187    static int WaitForThread( TO_THREAD_ID * thread_id );
    00188
    00189    /*
    00190    ** KillThread() -- force immediate, unclean, thread exit
    00191    **
    00192    **  Windows NT documentation gives a strong warning against
    00193    **  using TerminateThread(), since no stack cleanup, etc,
    00194    **  is done.
    00195    **
    00196    ** Argument:
    00197    **    tid = id of thread to kill
    00198    **
    00199    ** Returns:
    00200    **    WORM_STAT_SUCCESS if ok
    00201    **    WORM_STAT_FAILURE if an error
    00202    */
    00203    static int KillThread(  TO_THREAD_ID tid );
    00204
    00205
    00206    // That -- Pointer to the ThreadableObject requesting a
    00207    //         new internal thread.
    00208    //
    00209    static ThreadableObject * That;
    00210
    00211    // ThatMutex -- access lock for That pointer memory
    00212    //
    00213    static TMutex * ThatMutex;
    00214
    00215 public:
    00216
    00217    ThreadableObject()
    00218    {
    00219       if ( ThatMutex == NULL )
    00220       {
    00221          ThatMutex = new TMutex("ThreadMutex");
    00222       }
    00223    }
    00224
    00225    // GetThat() -- Method used by the file-scope function
    00226    //              StartObjectThread() to access the "That"
    00227    //              pointer which is the object requesting
    00228    //              the thread start.
    00229    //
    00230    static ThreadableObject * GetThat() { return That; }
    00231
    00232    /* StartThreadFunc() -- Method through which a newly-spawned
    00233    **                      thread returns to the "That" object
    00234    **                      to start execution.
    00235    **
    00236    ** PARAMETERS:
    00237    **      p_argument = pointer to any object containing
    00238    **                   requisite unique start conditions to
    00239    **                   the thread, possibly including
    00240    **                   indication of which method to execute.
    00241    */
    00242    virtual void StartThreadFunc( void * p_argument ) = 0;
    00243 };
    00244
    00245 #endif
    00246