G:/ScriptBasic/source/thread.c

Go to the documentation of this file.
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 

Generated on Sun Mar 12 23:56:31 2006 for ScriptBasic by  doxygen 1.4.6-NO