00001 /* 00002 FILE: thread.c 00003 HEADER: thread.h 00004 00005 TO_HEADER: 00006 00007 #ifdef WIN32 00008 #include <windows.h> 00009 #include <winbase.h> 00010 #include <io.h> 00011 #include <direct.h> 00012 #else 00013 #include <sys/file.h> 00014 #include <unistd.h> 00015 #include <dirent.h> 00016 #include <pwd.h> 00017 #include <netdb.h> 00018 #include <netinet/in.h> 00019 #include <pthread.h> 00020 #endif 00021 00022 #ifdef WIN32 00023 typedef HANDLE THREADHANDLE,*PTHREADHANDLE; 00024 typedef HANDLE MUTEX,*PMUTEX; 00025 #else 00026 typedef pthread_t THREADHANDLE,*PTHREADHANDLE; 00027 typedef pthread_mutex_t MUTEX,*PMUTEX; 00028 #endif 00029 00030 typedef struct _SHAREDLOCK { 00031 MUTEX mxWrite; 00032 MUTEX mxRead; 00033 MUTEX mxCounter; 00034 int dwReaders; 00035 } SHAREDLOCK, *PSHAREDLOCK; 00036 00037 00038 */ 00039 00040 #include "thread.h" 00041 00042 /*POD 00043 @c thread handling routines 00044 00045 This file implements global thread handling functions. If the programmer uses these functions instead 00046 of the operating system provided functions the result will be Windows NT I<and> UNIX portable program. 00047 These routines handling thread and mutex locking functions had been extensively tested in commercial 00048 projects. 00049 00050 CUT*/ 00051 00052 /*POD 00053 =H thread_CreateThread 00054 @c Create a new thread 00055 00056 This is a simplified implementation of the create thread interface. 00057 00058 The function creates a new B<detached> thread. 00059 If the thread can not be created for some reason the return value is the error 00060 code returned by the system call T<pthread_start> on UNIX or T<GetLastError> on NT. 00061 00062 If the thread was started the return value is 0. 00063 00064 /*FUNCTION*/ 00065 int thread_CreateThread(PTHREADHANDLE pThread, 00066 void *pStartFunction, 00067 void *pThreadParameter 00068 ){ 00069 /*noverbatim 00070 The arguments 00071 =itemize 00072 =item T<pThread> is a thread handle. This should be a pointer to a variable of type T<THREADHANDLE>. This 00073 argument is set to hold the thread handle returned by T<CreateThread> on NT or the pointer 00074 returned as first argument of T<pthread_create> under UNIX. This argument is not used further in this 00075 module but can be used if calling system dependant functions. 00076 =item T<pStartFunction> should be a pointer pointing to the start function where the thread should start. This 00077 is usually just the name of the function to start in the separate thread. 00078 =item T<pThreadParameter> is the pointer passed as argument to the start function. 00079 =noitemize 00080 00081 CUT*/ 00082 #ifdef WIN32 00083 DWORD TID; 00084 00085 *pThread = CreateThread(NULL, /* default security attribute */ 00086 0, /* default initial stack size */ 00087 (LPTHREAD_START_ROUTINE)pStartFunction, 00088 (LPVOID) pThreadParameter, 00089 0, /* should start immediately */ 00090 &TID); 00091 if( pThread != NULL ){ 00092 CloseHandle(*pThread); 00093 return 0; 00094 } 00095 return GetLastError(); 00096 #else 00097 int i; 00098 i = pthread_create(pThread, NULL , pStartFunction, pThreadParameter); 00099 if( i == 0 ) 00100 pthread_detach(*pThread); 00101 return i; 00102 #endif 00103 } 00104 00105 /*POD 00106 =H thread_ExitThread 00107 @c Exit from a thread 00108 00109 Exit from a thread created by R<CreateThread>. The implementation is simple 00110 and does not allow any return value from the thread. 00111 00112 /*FUNCTION*/ 00113 void thread_ExitThread( 00114 ){ 00115 /*noverbatim 00116 CUT*/ 00117 #ifdef WIN32 00118 ExitThread(0); 00119 #else 00120 pthread_exit(NULL); 00121 #endif 00122 } 00123 00124 /*POD 00125 =H thread_InitMutex 00126 @c Initialize a mutex object 00127 00128 This function initializes a T<MUTEX> variable. A T<MUTEX> variable can be used for exclusive access. 00129 If a mutex is locked another lock on that mutex will wait until the first lock is removed. If there are 00130 several threads waiting for a mutex to be released a random thread will get the lock when 00131 the actually locking thread releases the mutex. In other words 00132 if there are several threads waiting for a mutex there is no guaranteed order of the threads getting the 00133 mutex lock. 00134 00135 Before the first use of a T<MUTEX> variable it has to be initialized calling this function. 00136 00137 /*FUNCTION*/ 00138 void thread_InitMutex(PMUTEX pMutex 00139 ){ 00140 /*noverbatim 00141 Arguments: 00142 =itemize 00143 =item T<pMutex> should point to a mutex variable of the type T<MUTEX> 00144 =noitemize 00145 CUT*/ 00146 #ifdef WIN32 00147 *pMutex = CreateSemaphore(NULL,1,1,NULL); 00148 #else 00149 pthread_mutex_init(pMutex,NULL); 00150 #endif 00151 } 00152 00153 /*POD 00154 =H thread_FinishMutex 00155 @c Delete a mutex object 00156 00157 When a mutex is not used anymore by a program it has to be released to free the system resources 00158 allocated to handle the mutex. 00159 00160 /*FUNCTION*/ 00161 void thread_FinishMutex(PMUTEX pMutex 00162 ){ 00163 /*noverbatim 00164 Arguments: 00165 =itemize 00166 =item T<pMutex> should point to an initialized mutex variable of the type T<MUTEX> 00167 =noitemize 00168 CUT*/ 00169 #ifdef WIN32 00170 CloseHandle(*pMutex); 00171 #else 00172 pthread_mutex_destroy(pMutex); 00173 #endif 00174 } 00175 00176 /*POD 00177 =H thread_LockMutex 00178 @c Lock a mutex object 00179 00180 Calling this function locks the mutex pointed by the argument. If the mutex is currently locked the 00181 calling thread will wait until the mutex becomes available. 00182 00183 /*FUNCTION*/ 00184 void thread_LockMutex(PMUTEX pMutex 00185 ){ 00186 /*noverbatim 00187 Arguments: 00188 =itemize 00189 =item T<pMutex> should point to an initialized mutex variable of the type T<MUTEX> 00190 =noitemize 00191 CUT*/ 00192 #ifdef WIN32 00193 WaitForSingleObject(*pMutex,INFINITE); 00194 #else 00195 pthread_mutex_lock(pMutex); 00196 #endif 00197 } 00198 00199 /*POD 00200 =H thread_UnlockMutex 00201 @c Unlock a mutex object 00202 00203 Calling this function unlocks the mutex pointed by the argument. Calling this function on a mutex 00204 currently not locked is a programming error and results undefined result. Different operating system 00205 may repond different. 00206 00207 /*FUNCTION*/ 00208 void thread_UnlockMutex(PMUTEX pMutex 00209 ){ 00210 /*noverbatim 00211 Arguments: 00212 =itemize 00213 =item T<pMutex> should point to an initialized mutex variable of the type T<MUTEX> 00214 =noitemize 00215 CUT*/ 00216 #ifdef WIN32 00217 ReleaseSemaphore(*pMutex,1,NULL); 00218 #else 00219 pthread_mutex_unlock(pMutex); 00220 #endif 00221 } 00222 00223 00224 /*POD 00225 =H thread_shlckstry 00226 @c Shared locks 00227 00228 The following functions implement shared locking. These functions do not call system 00229 dependant functions. These are built on the top of the MUTEX locking functions. 00230 00231 A shareable lock can be B<READ> locked and B<WRITE> locked. When a shareable lock is READ locked 00232 another thread can also read lock the lock. 00233 00234 On the other hand a write lock is exclusive. A write lock can appear when there is no read lock on 00235 a shareable lock and not write lock either. 00236 00237 @cr 00238 00239 The story to understand the workings: 00240 00241 Imagine a reading room with several books. You can get into the room through a small 00242 entrance room, which is dark. To get in you have to switch on the light. The reading room 00243 has a light and a switch as well. You are not expected to read in the dark. The reading 00244 room is very large with several shelves that easily hide the absent minded readers and 00245 therefore the readers can not easily decide upon leaving if they are the last or not. This 00246 actually led locking up late readers in the dark or the opposite: lights running all the night. 00247 00248 To avoid this situation the library placed a box in the entrance room where each reader 00249 entering the room have to place his reader Id card. When they leave they remove the 00250 card. The first reader coming switches the light on, and the last one switches the light off. 00251 Coming first and leaving last is easily determined looking at the box after dropping the 00252 card or after taking the card out. If there is a single card after dropping the reader card 00253 into you are the first coming and if there is no card in it you took your one then you are 00254 the last. 00255 00256 To avoid quarreling and to save up energy the readers must switch on the light of the 00257 entrance room when they come into and should switch it off when they leave. However 00258 they have to do it only when they go into the reading room, but not when leaving. When 00259 someone wants to switch a light on, but the light is already on he or she should wait until 00260 the light is switched off. (Yes, this is a MUTEX.) 00261 00262 When the librarian comes to maintain ensures that no one is inside, switches the light of 00263 the entrance room on, and then switches the reading room light on. If someone is still 00264 there he cannot switch the light on as it is already switched on. He waits until the light is 00265 switched off then he switches it on. When he has switched the light of the reading room on 00266 he switches the light of the entrance room off and does his job in the reading room. Upon 00267 leaving he switches off the light of the reading room. 00268 00269 Readers can easily enter through the narrow entrance room one after the other. They can 00270 also easily leave. When the librarian comes he can not enter until all readers leave the 00271 reading room. Before getting into the entrance room he has equal chance as any of the 00272 readers. 00273 00274 CUT*/ 00275 00276 /*POD 00277 =H thread_InitLock 00278 @c Initialize a shareable lock 00279 00280 /*FUNCTION*/ 00281 void shared_InitLock(PSHAREDLOCK p 00282 ){ 00283 /*noverbatim 00284 CUT*/ 00285 thread_InitMutex( &(p->mxWrite) ); 00286 thread_InitMutex( &(p->mxRead) ); 00287 thread_InitMutex( &(p->mxCounter) ); 00288 p->dwReaders = 0; 00289 } 00290 00291 /*POD 00292 =H thread_FinishLock 00293 @c Finish a shareable lock 00294 00295 /*FUNCTION*/ 00296 void shared_FinishLock(PSHAREDLOCK p 00297 ){ 00298 /*noverbatim 00299 CUT*/ 00300 thread_FinishMutex( &(p->mxWrite) ); 00301 thread_FinishMutex( &(p->mxRead) ); 00302 thread_FinishMutex( &(p->mxCounter) ); 00303 } 00304 00305 /*POD 00306 =H thread_LockRead 00307 @c Lock a shareable lock for shared (read) lock 00308 00309 /*FUNCTION*/ 00310 void shared_LockRead(PSHAREDLOCK p 00311 ){ 00312 /*noverbatim 00313 CUT*/ 00314 int iReaders; 00315 thread_LockMutex( &(p->mxWrite) ); 00316 thread_LockMutex( &(p->mxCounter) ); 00317 p->dwReaders ++; 00318 iReaders = p->dwReaders; 00319 if( iReaders == 1 ) 00320 thread_LockMutex( &(p->mxRead) ); 00321 thread_UnlockMutex( &(p->mxCounter) ); 00322 thread_UnlockMutex( &(p->mxWrite) ); 00323 } 00324 00325 /*POD 00326 =H thread_LockWrite 00327 @c Lock a shareable lock for exclusive locking 00328 00329 /*FUNCTION*/ 00330 void shared_LockWrite(PSHAREDLOCK p 00331 ){ 00332 /*noverbatim 00333 CUT*/ 00334 thread_LockMutex( &(p->mxWrite) ); 00335 thread_LockMutex( &(p->mxRead) ); 00336 thread_UnlockMutex( &(p->mxWrite) ); 00337 } 00338 00339 /*POD 00340 =H thread_UnlockRead 00341 @c Unlock a sharebale lock that was locked shared 00342 00343 /*FUNCTION*/ 00344 void shared_UnlockRead(PSHAREDLOCK p 00345 ){ 00346 /*noverbatim 00347 CUT*/ 00348 int iReaders; 00349 thread_LockMutex( &(p->mxCounter) ); 00350 p->dwReaders --; 00351 iReaders = p->dwReaders; 00352 if( ! iReaders ) 00353 thread_UnlockMutex( &(p->mxRead) ); 00354 thread_UnlockMutex( &(p->mxCounter) ); 00355 } 00356 00357 /*POD 00358 =H thread_UnlockWrite 00359 @c Unlock a sharebale lock that was locked exclusive 00360 00361 /*FUNCTION*/ 00362 void shared_UnlockWrite(PSHAREDLOCK p 00363 ){ 00364 /*noverbatim 00365 CUT*/ 00366 thread_UnlockMutex( &(p->mxRead) ); 00367 } 00368