1 // 2 // Thread.h: header file 3 // 4 // Copyright (C) Walter E. Capers. All rights reserved 5 // 6 // This source is free to use as you like. If you make 7 // any changes please keep me in the loop. Email them to 8 // walt.capers@comcast.net. 9 // 10 // PURPOSE: 11 // 12 // To implement Win32 threading as a C++ object 13 // 14 // REVISIONS 15 // ======================================================= 16 // Date: 10.24.07 17 // Name: Walter E. Capers 18 // Description: File creation 19 // 20 // Date: 10.24.07 11:49 am 21 // Name: Walter E. Capers 22 // Description: Added SetIdle function to allow the idle time to be altered 23 // independent of the SetThreadType member function. 24 // Date: 10.31.07 25 // Name: Walter E. Capers 26 // Description: Added support for beginthreadex 27 // To use compile with -DUSE_BEGIN_THREAD 28 // 29 // 30 31 #ifndef THREAD_CLASS 32 #define THREAD_CLASS 33 34 #ifndef WINDOWS 35 #if defined(_WIN32) || defined(_WIN64) 36 #define WINDOWS 37 #endif 38 #endif 39 #ifdef __APPLE__ 40 #define VMS 41 #endif 42 43 #ifndef WINDOWS 44 #include <stdio.h> 45 #include <string.h> 46 //#include <malloc.h> 47 #include <memory.h> 48 #include <pthread.h> 49 #include <stdlib.h> 50 #include <time.h> 51 #include <errno.h> 52 typedef unsigned char BOOL; 53 #define TRUE 1 54 #define FALSE 0 55 typedef long DWORD; 56 typedef void *LPVOID; 57 #else 58 #include "afx.h" 59 /* #include <windows.h> */ 60 #include <stdio.h> 61 #endif 62 63 #if defined(AS400) || defined(OS400) 64 typedef pthread_id_np_t ThreadId_t; 65 #elif defined(VMS) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) 66 typedef pthread_t ThreadId_t; 67 #else 68 #ifdef USE_BEGIN_THREAD 69 typedef unsigned ThreadId_t; 70 #else 71 typedef DWORD ThreadId_t; 72 #endif 73 #endif 74 75 #include <common/MutexClass.h> 76 #include <common/EventClass.h> 77 78 #define QUEUE_SIZE 100 79 #define DEFAULT_STACK_SIZE 0 80 #ifndef WINDOWS 81 void Sleep( unsigned int mseconds); 82 #endif 83 84 #ifndef ASSERT 85 #if defined(DEBUG) || defined(_DEBUG) 86 #define ASSERT(test) if( !(test) ) { \ 87 fprintf(stderr,"\nASSERT(%s) FAILS, %s line %d\n",#test,__FILE__, __LINE__); exit(0);} 88 #else 89 #define ASSERT(test) 90 #endif 91 #endif 92 93 94 typedef enum { 95 ThreadStateBusy, // thread is currently handling a task 96 ThreadStateWaiting, // thread is waiting for something to do 97 ThreadStateDown, // thread is not running 98 ThreadStateShuttingDown, // thread is in the process of shutting down 99 ThreadStateFault // an error has occured and the thread could not 100 // be launched 101 } ThreadState_t; 102 103 typedef enum { 104 ThreadTypeHomogeneous, 105 ThreadTypeSpecialized, 106 ThreadTypeIntervalDriven, 107 ThreadTypeNotDefined } ThreadType_t; 108 109 110 typedef enum { 111 TaskStatusNotSubmitted, 112 TaskStatusWaitingOnQueue, 113 TaskStatusBeingProcessed, 114 TaskStatusCompleted } TaskStatus_t; 115 116 class CTask 117 { 118 private: 119 TaskStatus_t m_state; 120 ThreadId_t m_dwThread; 121 public: 122 CMutexClass m_mutex; 123 SetTaskStatus(TaskStatus_t state)124 void SetTaskStatus(TaskStatus_t state) 125 { 126 m_mutex.Lock(); 127 m_state=state; 128 m_mutex.Unlock(); 129 } 130 SetId(ThreadId_t * pid)131 void SetId(ThreadId_t *pid) 132 { 133 memcpy(&m_dwThread,pid,sizeof(ThreadId_t)); 134 } 135 136 /** 137 * 138 * Wait 139 * waits for upto timeoutSeconds for a task 140 * to complete 141 * 142 **/ Wait(int timeoutSeconds)143 BOOL Wait(int timeoutSeconds) 144 { 145 timeoutSeconds = timeoutSeconds * 1000; 146 if( Status() != TaskStatusCompleted && 147 timeoutSeconds > 0 ) 148 { 149 Sleep(100); 150 timeoutSeconds = timeoutSeconds - 100; 151 } 152 if( Status() == TaskStatusCompleted ) return TRUE; 153 return FALSE; 154 } 155 156 /** 157 * 158 * Status 159 * returns current state of a task 160 * 161 **/ Status()162 TaskStatus_t Status() 163 { 164 TaskStatus_t state ; 165 166 m_mutex.Lock(); 167 state = m_state; 168 m_mutex.Unlock(); 169 return state; 170 } 171 Thread(ThreadId_t * pId)172 void Thread(ThreadId_t *pId) 173 { 174 memcpy(pId,&m_dwThread,sizeof(ThreadId_t)); 175 } 176 CTask()177 CTask(){m_state=TaskStatusNotSubmitted; memset(&m_dwThread,0,sizeof(ThreadId_t)); } ~CTask()178 ~CTask(){} 179 virtual BOOL Task()=0; 180 }; 181 182 183 class CThread 184 #ifdef WINDOWS 185 : public CObject // use CObject as a base class so object can be used in lists and 186 // object arrays 187 #endif 188 { 189 private: 190 CEventClass m_event; // event controller 191 int m_StopTimeout; // specifies a timeout value for stop 192 // if a thread fails to stop within m_StopTimeout 193 // seconds an exception is thrown 194 195 BOOL m_bRunning; // set to TRUE if thread is running 196 #ifdef WINDOWS 197 HANDLE m_thread; // thread handle 198 #else 199 pthread_t m_thread; // thread handle 200 #endif 201 ThreadId_t m_dwId; // id of this thread 202 LPVOID *m_lppvQueue; // task que 203 unsigned int m_chQueue; // que depth 204 unsigned int m_queuePos; // current que possition 205 LPVOID m_lpvProcessor; // data which is currently being processed 206 ThreadState_t m_state; // current state of thread see thread state data 207 // structure. 208 DWORD m_dwIdle; // used for Sleep periods 209 ThreadType_t m_type; 210 DWORD m_stackSize; // thread stack size 211 #define NO_ERRORS 0 212 #define MUTEX_CREATION 0x01 213 #define EVENT_CREATION 0x02 214 #define THREAD_CREATION 0x04 215 #define UNKNOWN 0x08 216 #define ILLEGAL_USE_OF_EVENT 0x10 217 #define MEMORY_FAULT 0x20 218 #define EVENT_AND_TYPE_DONT_MATCH 0x40 219 #define STACK_OVERFLOW 0x80 220 #define STACK_EMPTY 0x100 221 #define STACK_FULL 0x200 222 223 DWORD m_dwObjectCondition; 224 BOOL Push(LPVOID lpv); 225 BOOL Pop(); 226 BOOL Empty(); 227 public: 228 /** 229 * 230 * user definable member functions 231 * 232 **/ 233 CMutexClass m_mutex; // mutex that protects threads internal data 234 235 virtual BOOL OnTask(LPVOID lpvData); // called when an event occurs 236 virtual BOOL OnTask(); // called when a time interval has elapsed 237 238 CThread(void); 239 ~CThread(void); 240 #ifdef WINDOWS 241 #ifdef USE_BEGIN_THREAD 242 friend unsigned __stdcall _THKERNEL(LPVOID lpvData); 243 #else 244 friend DWORD WINAPI _THKERNEL( LPVOID lpvData ); 245 #endif 246 #else 247 friend LPVOID _THKERNEL(LPVOID lpvData); 248 #endif 249 BOOL FromSameThread(); 250 float PercentCapacity(); 251 void WaitTillExit(); 252 BOOL KernelProcess(); 253 BOOL Event(LPVOID lpvData=NULL); 254 BOOL Event(CTask *pvTask); SetOnStopTimeout(int seconds)255 void SetOnStopTimeout(int seconds ) { m_StopTimeout = seconds; } 256 BOOL SetQueueSize( unsigned int ch ); 257 BOOL Stop(); 258 BOOL Start(); GetId(ThreadId_t * pId)259 void GetId(ThreadId_t *pId) { memcpy(pId,&m_dwId,sizeof(ThreadId_t)); } // returns thread id 260 ThreadState_t ThreadState(); 261 BOOL PingThread(DWORD dwTimeout=0); 262 BOOL AtCapacity(); 263 #ifdef WINDOWS 264 void SetPriority(DWORD dwPriority=THREAD_PRIORITY_NORMAL); 265 #else 266 void SetPriority(DWORD dwPriority=0); 267 #endif GetErrorFlags()268 DWORD GetErrorFlags() { return m_dwObjectCondition; } // returns state of object 269 void SetThreadType(ThreadType_t typ=ThreadTypeNotDefined,DWORD dwIdle=100); 270 void SetIdle(DWORD dwIdle=100); 271 unsigned int GetEventsPending(); ThreadIdsEqual(ThreadId_t * p1,ThreadId_t * p2)272 static BOOL ThreadIdsEqual(ThreadId_t *p1, 273 ThreadId_t *p2) 274 { 275 #if defined(AS400)||defined(OS400) 276 return(( memcmp(p1,p2,sizeof(ThreadId_t))==0)?TRUE:FALSE); 277 #elif defined(VMS) || defined(__NetBSD__) 278 return (( pthread_equal(*p1,*p2) )?TRUE:FALSE ); 279 #else 280 return ((*p1 == *p2)?TRUE:FALSE); 281 #endif 282 283 } 284 ThreadId()285 static ThreadId_t ThreadId() 286 { 287 ThreadId_t thisThreadsId ; 288 #if defined(AS400) || defined(OS400) 289 pthread_t thread; 290 #endif 291 292 #ifdef WINDOWS 293 thisThreadsId = (ThreadId_t)GetCurrentThreadId(); 294 #else 295 296 #if defined(AS400) || defined(OS400) 297 thread = pthread_self(); 298 pthread_getunique_np(&thread,&thisThreadsId); 299 #elif defined(ALPHA) || defined(DEC) || defined(VMS) 300 #ifdef VMS 301 thisThreadsId = pthread_self(); 302 #else 303 thisThreadsId = pthread_getsequence_np(pthread_self()); 304 #endif 305 #else 306 thisThreadsId = pthread_self(); 307 #endif 308 #endif 309 return thisThreadsId; 310 } 311 312 313 }; 314 #endif 315 316