RU/2: Форум. Общение пользователей и разработчиков OS/2 (eCS). : Ответить на сообщение
Имя:
e-mail:
FIDO:
Home page:
сохранить данные о вас
Тема:
> A comparison between OS/2 and Linux thread programming > > > > This article covers mapping of threading and synchronization primitives. > > Threads > A thread is the basic unit of execution in OS/2. Threads are the dispatchable units within an OS/2 process. Thread scheduling and > priority is handled entirely in the kernel. > > The Linux kernel uses a process model rather than a threading model. However, the Linux kernel provides a lightweight process framework for creating threads, > and the actual thread implementation is in the user space. Currently there are various threading libraries available (LinuxThreads, NGPT, NPTL, and so on). > Research for this document was done using the LinuxThreads library, but the information herein is also applicable to Red Hat's Native POSIX Threading Library > (NPTL) > > This section describes threading in OS/2 and in Linux. It covers the calls for creating threads, setting its attributes, and changing its priority. > > The thread mapping table is as follows: > > Table 1. Thread mapping table > OS/2 > Linux > Classification > _beginthread > pthread_create > pthread_attr_init > pthread_attr_setstacksize > pthread_attr_destroy > mappable > _endthread > pthread_exit > mappable > DosWaitThread > pthread_join > pthread_attr_setdetachstate > pthread_detach > mappable > DosSetPriority > Processes > setpriority > sched_setscheduler > sched_setparam > Threads > pthread_setschedparam > pthread_setschedpolicy > pthread_attr_setschedparam > pthread_attr_setschedpolicy > context-specific > > > The Classification column indicates whether the OS/2 construct is mappable or context-specific: > > Mappable: The OS/2 construct can be mapped to the specified Linux construct(s) by closely examining the types, parameters, return codes, and the like. > Both the OS/2 and Linux constructs provide similar functionality > Context-specific: The given OS/2 construct may or may not have an equivalent construct in Linux OR Linux may have more than one construct which > provides similar functionality. The decision to use a specific Linux construct(s) then depends on the application context. > > Thread creation > The system call _beginthread is used for spawning threads in OS/2: > > int _beginthread(void (*start_address) (void *), (void *) stack, > unsigned stack_size, void *arg); > > Linux uses the pthread library call pthread_create() to spawn a thread: > > int pthread_create (pthread_t *thread_id, pthread_attr_t *threadAttr, > void * (*start_address)(void *), void * arg); > > Specifying the thread function > The parameter start_address for the OS/2 system call _beginthread is the address of the function > that the newly created thread will execute. The thread function must be declared and compiled using > _Optlink linkage. > > The parameter start_address for the Linux library call pthread_create() is the address of the > function that the newly created thread will execute. > > Parameter passing to the thread function > In OS/2, the parameter arg for the system call _beginthread() is used to specify the parameter to be > passed to the newly created thread. It specifies the address of the data item to be passed to the new thread. > > In Linux, the parameter arg for the library call pthread_create() is used to specify the parameter to be > passed to the new thread > > Setting the stack size > The parameter stack_size for the OS/2 system call _beginthread() is the size of stack, in bytes, that is > to be allocated for the new thread. The stack size should be a non-zero multiple of 4K and a minimum of 8K. > > In Linux, the stack size is set in the pthread attributes object; that is, the parameter threadAttr of type > pthread_attr_t is passed to the library call pthread_create(). This object needs to be initialized > by the call pthread_attr_init() before setting any attributes. The attribute object is destroyed using the > call pthread_attr_destroy(): > > int pthread_attr_init(pthread_attr_t *threadAttr); > int pthread_attr_destroy(pthread_attr_t *threadAttr); > > Note that all of the pthread_attr_setxxxx calls achieve similar functionality to the pthread_xxxx > calls (if available) except that pthread_attr_xxxx can only be used before thread creation to update the attribute object that will be passed as a parameter to > pthread_create. Meanwhile, pthread_xxxx calls can be used anytime after the thread has been created > > The stack size is set using the call pthread_attr_setstacksize(): > > int pthread_attr_setstacksize(pthread_attr_t *threadAttr, int > stack_size); > > Thread states > In OS/2 there are no explicit thread states maintained with respect to thread termination. However, it is possible to use DosWaitThread() call, which allows a > thread to wait explicitly on the termination of a specific or non-specific thread within the process. > > In Linux, threads are by default created in joinable state. In joinable state, another thread can synchronize on the thread's termination and recover its termination > code using the function pthread_join(). The thread resources of the joinable thread are released only after it is joined. > > OS/2 uses DosWaitThread() to wait for a thread to terminate: > > APIRET DosWaitThread(PTID ptid, ULONG option); > > Linux uses pthread_join to do the same: > > int pthread_join(pthread_t *thread, void **thread_return); > > In the detached state, the thread resources are immediately freed when it terminates. The detached state can be set by calling > pthread_attr_setdetachstate() on the thread attribute object. > > int pthread_attr_setdetachstate (pthread_attr_t *attr, int > detachstate); > > A thread created in a joinable state can later be put into a detached state using the pthread_detach() call: > > int pthread_detach (pthread_t id); > > Thread exit > In OS/2, the system call _endthread() is used terminate the thread. > > The Linux equivalent for this is the library call pthread_exit(). The retval is the return value of the thread and it can be retrieved from another thread by > calling pthread_join(): > > int pthread_exit(void* retval); > > Changing priority > OS/2 uses the system call DosSetPriority() to change the priority of a process or thread of a running process: > > int DosSetPriority(int scope, int class, int delta, int id); > > In this example, scope is PRTYS_PROCESS for a process; PRTYS_THREAD for a thread level is the priority level. The different priority levels allowed are: > > No change : PRTYC_NOCHANGE > Idle-time : PRTYC_IDLETIME > Regular : PRTYC_REGULAR > Time-critical : PRTYC_TIMECRITICAL > Fixed high : PRTYC_FOREGROUNDSERVER > > Where delta is the priority change to be applied to the priority level of the process. This value must range from -31 to +31. The higher the value, the higher the > priority. The current process or thread has an id of 0. > > Linux provides a variety of calls to modify or change thread priority. Different calls should be used depending on the application context. > > Normal or regular processes/threads > The Linux system call setpriority() is used to set or modify priority levels for normal processes and threads. The parameter scope is PRIO_PROCESS. Set > id to 0 to change the current process (or thread) priority. Again, delta is the priority value -- this time, in the range -20 to 20. Note also that in Linux, a lower delta > value means a higher priority. So you set +20 for IDLETIME priority and 0 for REGULAR priority. > > In OS/2 the priority range is from 0 (lower priority) to 31 (higher priority). But in Linux the priority range for normal non-realtime processes is from -20 (higher) > to +20 (lower priority). This has to be mapped before being used. > > int setpriority(int scope, int id, int delta); > > Time-critical and realtime processes and threads > The Linux system call sched_setscheduler can be used to change the scheduling priority and policy of a running process: > > int sched_setscheduler(pit_t pid, int policy, const struct sched_param *param); > > The parameter "policy" is the scheduling policy. The possible values for policy are SCHED_OTHER (for regular non-realtime scheduling), SCHED_RR (realtime > round-robin policy), and SCHED_FIFO (realtime FIFO policy). > > > struct sched_param { > ... > int sched_priority; > ... > }; > > > > Here, param is a pointer to a structure representing scheduling priority. It can range from 1 to 99 only for realtime policies. For others (normal non-realtime > processes) it is zero. > > In Linux, for a known scheduling policy, it is also possible to change only the process priority by using the system call sched_setparam: > > int sched_setparam(pit_t pid, const struct sched_param *param); > > The LinuxThreads library call pthread_setschedparam is the thread version of sched_setscheduler and is used to dynamically change the > scheduling priority and policy for a running thread: > > int pthread_setschedparam(pthread_t target_thread, int policy, > const struct sched_param *param); > > The parameter target_thread indicates the thread whose priority is to be changed and param indicates the priority. > > The LinuxThreads library calls pthread_attr_setschedpolicy and pthread_attr_setschedparam can be used to set the scheduling policy > and the priority level to the thread attribute object before the thread is created: > > int pthread_attr_setschedpolicy(pthread attr_t *threadAttr, int policy); > > int pthread_attr_setschedparam(pthread attr_t *threadAttr, const > struct sched_param *param); > > Let's see an example that highlights the OS/2 to Linux mapping with respect to thread creation and priority changes. > > Thread examples > In this OS/2 example, thread1 is a regular thread, thread2 is a time-critical realtime thread: > > Listing 1. OS/2 thread code > > main () { > enum {StackSize = 120*1024}; /* stack size set to 120 K */ > /* create a thread */ > int thread1 = _beginThread (RegularThread, NULL, StackSize, > NULL); > int thread2 = _beginThread (CriticalThread, NULL, > StackSize, NULL); > } > > /* Normal /Regular Priority Thread */ > static void RegularThread (void *) { > /* Set the priority of the thread. 0 is passed as an > argument to identify the current thread */ > int iRc = DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, 20, > 0); > _endThread(); > } > > /* Realtime time critical Priority Thread */ > static void CriticalThread (void *) { > int iRc = DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, > 20, 0); > _endThread(); > } > > > > The Linux equivalent for the above OS/2 code: > > Listing 2. Equivalent Linux thread code > > #define STATIC 0 > static void * RegularThread (void *); > static void * CriticalThread (void *); > /* Regular non-realtime Thread function */ > static void * RegularThread (void *d) > { > int priority = 10; //0 for Regular, +20 for Idletime > /* Set the priority - normal non-realtime priority */ > int irc = setpriority(PRIO_PROCESS, 0, priority); > pthread_exit(NULL); > } > /* Time Critical Realtime Thread function */ > static void * CriticalThread (void *d) > { > if (STATIC == 0) { > /* change the thread priority dynamically */ > struct sched_param param; // scheduling priority > int policy = SCHED_RR; // scheduling policy > /* Get the current thread id */ > pthread_t thread_id = pthread_self(); > /* To set the scheduling priority of the thread */ > param.sched_priority = 99; > int irc = pthread_setschedparam(thread_id, policy, ¶m); > } > pthread_exit(NULL); > } > int main (void) > { > pthread_t thread1, thread2; // thread identifiers > pthread_attr_t threadAttr1, threadAttr2; // thread attributes > struct sched_param param; // scheduling priority > int policy = SCHED_RR; // scheduling policy - real time > int irc, rc; > rc = pthread_attr_init(&threadAttr1); /* init the attr 1*/ > rc = pthread_attr_init(&threadAttr2); /* init the attr 2*/ > /* Set the stack size of the thread */ > irc = pthread_attr_setstacksize(&threadAttr1, 120*1024); > irc = pthread_attr_setstacksize(&threadAttr2, 120*1024); > /* Set thread to detached state. No need for pthread_join*/ > irc = pthread_attr_setdetachstate(&threadAttr1, > PTHREAD_CREATE_DETACHED); > irc = pthread_attr_setdetachstate(&threadAttr2, > PTHREAD_CREATE_DETACHED); > if (STATIC == 1) { > /* priority is set statically */ > /* Set the policy of the thread to real time*/ > irc = pthread_attr_setschedpolicy(&threadAttr2, policy); > /* Set the scheduling priority of the thread - max > priority*/ > param.sched_priority = 99; > irc = pthread_attr_setschedparam(&threadAttr2, ¶m); > } > /* Create the threads */ > irc = pthread_create(&thread1, &threadAttr1, RegularThread, NULL); > irc = pthread_create(&thread2, &threadAttr2, CriticalThread, > NULL); > /* Destroy the thread attributes */ > irc = pthread_attr_destroy(&threadAttr1); > irc = pthread_attr_destroy(&threadAttr2); > } > > > > Mutexes > Various points need to be considered in the mapping process of a mutex, including: > > Type of mutex: OS/2 mutex semaphores are recursive by default whereas this is not the case in Linux. > Initial state: A mutex in OS/2 can be owned on creation whereas this support is not available in Linux. To achieve the same in Linux, the mutex should > be locked explicitly after creation. > Semaphores: OS/2 supports named and un-named semaphores whereas the current implementation of Linux pthreads does not support this option. > Timeout: In OS/2, timeout can be specified while acquiring the mutex. In Linux this option is not available (a workaround follows later in this article). > > The mutex mapping table is as follows: > > Table 2. Mutex mapping table > OS/2 > Linux > Classification > DosCreateMutexSem > DosRequestMutexSem > DosReleaseMutexSem > DosCloseMutexSem > pthread_mutex_init > pthread_mutex_lock/pthread_mutex_trylock > pthread_mutex_unlock > pthread_mutex_destroy > Mappable > > > Creating a mutex > In OS/2, the system call DosCreateMutexSem() is used to create the Mutex: > > APIRET DosCreateMutexSem (PSZ pszName, PHMTX phmtx, ULONG flAttr, BOOL32 fState); > > The parameter pszName takes the ASCII name of the mutex. > > The pthread library call pthread_mutex_init() is used to create the mutex in Linux: > > int pthread_mutex_init(pthread_mutex_t *mutex, const > pthread_mutexattr_t *mutexattr); > > There are three "kinds" of mutex in Linux. The mutex "kind" determines what happens if a thread attempts to lock a mutex it already owns with > pthread_mutex_lock: > > Fast mutex: While trying to lock the mutex using pthread_mutex_lock() the calling thread suspends forever. > Recursive mutex:pthread_mutex_lock() returns immediately with a success return code. > Error check mutex:pthread_mutex_lock() returns immediately with the error code EDEADLK. > > The mutex "kind" can be set in two ways. The static way of setting is as follows: > > pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; > /* For Fast mutexes */ > pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; > /* For recursive mutexes */ > pthread_mutex_t errchkmutex = > PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;/* For errorcheck mutexes */ > > Another way of setting mutex "kind" is by using a mutex attribute object. To do this, pthread_mutexattr_init() is called to initialize the object > followed by a pthread_mutexattr_settype(), which sets the "kind" of the mutex: > > int pthread_mutexattr_init(pthread_mutexattr_t *attr); > int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind); > > The parameter "kind" takes the following values: > > PTHREAD_MUTEX_FAST_NP > PTHREAD_MUTEX_RECURSIVE_NP > PTHREAD_MUTEX_ERRORCHECK_NP > > The attribute can be destroyed using pthread_mutexattr_destroy(): > > int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); > > Locking or acquiring a mutex > OS/2 uses DosRequestMutexSem() to lock (acquire) the mutex: > > APIRET DosRequestMutexSem(HMTX hmtx, ULONG ulTimeout); > > The parameter ulTimeOut is used to specify the maximum amount of time the thread is to be blocked: > > On Linux, the pthread library calls pthread_mutex_lock() and pthread_mutex_trylock() are used to acquire a mutex: > > int pthread_mutex_lock(pthread_mutex_t *mutex); > int pthread_mutex_trylock(pthread_mutex_t *mutex); > > The first of these, pthread_mutex_lock(), is a blocking call -- which means that if the mutex is already locked by another thread, > pthread_mutex_lock() suspends the calling thread until the mutex is unlocked. > > On the other hand, pthread_mutex_trylock() returns immediately if the mutex is already locked by another thread. > > Note that in Linux, the timeout option is not available. This same effect can be achieved by issuing a non-blocking pthread_mutex_trylock() call along > with a delay in a loop, which counts the timeout value. (Refer to Listing 5 for sample code). > > Unlocking or releasing a mutex > OS/2 uses DosReleaseMutexSem() to relinquish ownership of a mutex semaphore: > > APIRET DosReleaseMutexSem(HMTX hmtx); > > Linux uses pthread_mutex_unlock() to release (unlock) the mutex: > > int pthread_mutex_unlock(pthread_mutex_t *mutex); > > Note that mutex functions are not async-signal safe and should not be called from a signal handler. In particular, calling pthread_mutex_lock or > pthread_mutex_unlock from a signal handler may deadlock the calling thread. > > Destroying a mutex > In OS/2, DosCloseMutexSem() is used to close a mutex semaphore: > > APIRET DosCloseMutexSem (HMTX hmtxSem); > > On Linux, pthread_mutex_destroy() destroys a mutex object, freeing the resources it might hold. It also checks whether the mutex is unlocked at that > time: > > int pthread_mutex_destroy(pthread_mutex_t *mutex); > > Setting state > The parameter fState of the DosCreateMutexSem() is used to specify the initial state of the mutex in OS/2. fState can take two possible values: > > value 1 creates a mutex with initially owned state > value 0 creates a mutex with initially un-owned state > > In Linux, the initial state of the mutex cannot be set using the pthread_mutex_init() call. But it can be achieved by following steps: > > 1.Create a mutex using pthread_mutex_init() > 2.Lock (acquire) the mutex using pthread_mutex_lock() > > Mutex examples > > Listing 3. OS/2 mutex code > > hmtx hmtxSem; // semaphore handle > unsigned long ulRc; // return code > > /* Create a un named mutex semaphore */ > ulRc = DosCreateMutexSem (NULL, &hmtxSem, 0, FALSE); > > ulRc = DosRequestMutexSem (hmtxSem, (unsigned long) > SEM_INDEFINITE_WAIT); > > /* Access the shared resource */ > ... > > /* Release the mutex */ > ulRc = DosReleaseMutexSem(hmtxSem); > ... > > /* Closes the semaphore */ > ulrc = DosCloseMutexSem (hmtxSem); > > > > Compare this to the following Linux code: > > Listing 4. Linux mutex code > > /* Declare the mutex */ > pthread_mutex_t mutex; > /* Attribute for the mutex */ > pthread_mutexattr_t mutexattr; > /* Set the mutex as a recursive mutex */ > pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP); > > /* create the mutex with the attributes set */ > pthread_mutex_init(&mutex, &mutexattr); > > /* lock the mutex */ > pthread_mutex_lock (&mutex); > > /* access the shared resource */ > .. > > /* unlock the mutex */ > pthread_mutex_unlock (&mutex); > ... > > /* destroy the attribute */ > pthread_mutexattr_destroy(&mutexattr) > /* Close/destroy the semaphore */ > irc = pthread_mutex_destroy (&mutex); > > > > The next example illustrates how to simulate the timeout option while trying to aquire a mutex: > > Listing 5. Simulating a timeout in Linux > > #define TIMEOUT 100 /* 1 sec */ > struct timespec delay; > /* Declare the mutex */ > pthread_mutex_t mutex; > > while (timeout < TIMEOUT ) { > delay.tv_sec = 0; > delay.tv_nsec = 1000000; /* 1 milli sec */ > > irc = pthread_mutex_trylock(&mutex); > if (!irc) { > /* we now own the mutex */ > break; > } > else { > /* check whether somebody else has the mutex */ > if (irc == EPERM ) { > /* sleep for delay time */ > nanosleep(&delay, NULL); > timeout++ ; > } > else{ > /* error */ > } > } > } > > > > Semaphores > Linux provides POSIX semaphores as well as pthread conditional variables to map OS/2 event semaphore constructs (Linux also provides SVR-compliant semop, > semctl, and similar calls, but for the purposes of this document we are limiting ourselves to the POSIX and LinuxThreads implementations). Both have their share > of pros and cons. It is up to the user's discretion to use either of them based on application logic. The various points that needs to be considered in the mapping > process of the event semaphore are: > > Type of semaphore: OS/2 supports both named and un-named event semaphores and the named semaphores are shared across processes. Linux does > not support this option. > Initial state: In OS/2, the semaphore can have an initial value. In Linux, POSIX semaphore supports this functionality but pthreads does not. This needs > to be considered when using pthreads. > Timeout: OS/2 event semaphores supports timed wait. In Linux the POSIX semaphore implementation supports only indefinite wait (blocking). The > pthreads implementation supports both blocking as well as timeouts. The pthread_cond_timedwait() call provides a timeout value during wait > and pthread_cond_wait() is used for indefinite wait. > Signaling: In OS/2, signaling a semaphore wakes up all the threads that are waiting on the semaphore. In Linux, the POSIX thread implementation > wakes up only one thread at a time while the pthreads implementation has a pthread_cond_signal() that wakes up one thread and a > pthread_cond_broadcast() call that signals all the threads waiting on the semaphore. > Synchronicity: An event semaphore is asynchronous in OS/2. In Linux, a POSIX semaphore is asynchronous whereas a pthreads conditional variable is > synchronous. > > To sum it up, POSIX semaphores can be considered when no timed waits or broadcast wakeup are required. If the application logic requires broadcast wakeups > and timeouts, pthread conditional variable can be used. > > The Semaphore mapping table is as below: > > Table 3. Semaphore mapping table > OS/2 > POSIX Linux > calls > pthread Linux calls > Classification > DosCreateEventSem > sem_init > pthread_cond_init > context-specific > DosPostEventSem > sem_post > pthread_cond_signal / > pthread_cond_broadcast > context-specific > DosWaitEventSem > sem_wait/sem_trywait > pthread_cond_wait / > pthread_cond_timedwait > context-specific > DosCloseEventSem > sem_destroy > pthread_cond_destroy > context-specific > > > Creating an event semaphore > OS/2 uses DosCreateEventSem() call to create an event semaphore: > > APIRET DosCreateEventSem (PSZ pszName,PHEV phev, ULONG flAttr, BOOL32 fState); > > Here, pszName is a pointer to ASCII name of the semaphore. If this parameter is NULL, DosCreateEventSem() creates a un-named event semaphore. > fState is used to set the state of the event semaphore. If it is 0, the semaphore is initially reset, and if it is 1, the semaphore is initially posted. > > In Linux, the call sem_init() creates a POSIX semaphore: > > int sem_init(sem_t *sem, int pshared, unsigned int value); > > Where value (semaphore count) is set to the initial value of the semaphore. > > Linux pthreads uses pthread_cond_init() to create a conditional variable: > > int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr); > > Conditional variables of type pthread_cond_t can be initialized statically, using the constant PTHREAD_COND_INITIALIZER. They can also be > initialized using pthread_condattr_init(), which initializes the attributes associated with the conditional variable. The call > pthread_condattr_destroy() is used to destroy the attributes: > > int pthread_condattr_init(pthread_condattr_t *attr); > int pthread_condattr_destroy(pthread_condattr_t *attr); > > Waiting on an event semaphore > In OS/2, DosWaitEventSem() is used to block a thread and wait on the event semaphore: > > APIRET DosWaitEventSem (HEV hev, ULONG ulTimeOut); > > Where the parameter ulTimeOut specifies the timeout value. If the semaphore is not posted within the specified time, the DosWaitEventSem() call will > return with an error code. If -1 is specified as timeout value, it blocks the calling thread indefinitely. > > Linux POSIX semaphores use sem_wait() to suspend the calling thread until the semaphore has a non-zero count. It then atomically decreases the semaphore > count: > > int sem_wait(sem_t * sem) > > The timeout option is not available in POSIX semaphore. This can be achieved by issuing non-blocking sem_trywait() within a loop, which counts the > timeout value: > > int sem_trywait(sem_t * sem); > > Linux pthreads uses pthread_cond_wait() to block the calling thread indefinitely: > > int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex); > > On the other hand, if the calling thread needs to be blocked for a specific time, then pthread_cond_timedwait() is used to block the thread. If the > conditional variable is not posted within the specified time, pthread_cond_timedwait() returns with an error: > > int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t > *mutex,const struct timespec *abstime); > > Here, the abstime parameter specifies an absolute time (specifically, the time elapsed since 00:00:00 GMT, January 1, 1970.) > > Signaling an event semaphore > OS/2 uses DosPostEventSem() to post an event semaphore. This wakes up all the threads that are waiting on the semaphore: > > APIRET DosPostEventSem (HEV hev); > > Linux POSIX semaphores use sem_post() to post an event semaphore. This wakes up any one of the threads blocked on the semaphore: > > int sem_post(sem_t * sem); > > The call pthread_cond_signal() is used in LinuxThreads to wake up a thread waiting on the conditional variable, while > pthread_cond_broadcast() is used to wake up all the threads that are waiting on the conditional variable. > > int pthread_cond_signal(pthread_cond_t *cond); > int pthread_cond_broadcast(pthread_cond_t *cond); > > Note that condition functions are not async-signal safe, and should not be called from a signal handler. In particular, calling pthread_cond_signal or > pthread_cond_broadcast from a signal handler may deadlock the calling thread. > > Destroying an event semaphore > OS/2 uses DosCloseEventSem() to destroy the event semaphore: > > APIRET DosCloseEventSem (HEV hev); > > Linux POSIX semaphores use sem_destroy() to destroy the semaphore: > > int sem_destroy(sem_t * sem); > > In Linux pthreads, pthread_cond_destroy() is used to destroy the conditional variable: > > int pthread_cond_destroy(pthread_cond_t *cond); > > Event semaphore examples > > Listing 6. OS/2 semaphore code > > HEV hevIpcInterrupt; > unsigned long ulPostCnt = 0; > unsigned long ulrc; // return code > unsigned long ulTimeout = 10 ; // timeout value > > /* create event semaphore */ > DosCreateEventSem (NULL, &hevIpcInterrupt, 0, TRUE); > > /* In Thread A */ > /* Wait forever for event to be posted */ > DosWaitEventSem (hevIpcInterrupt, (unsigned long) > SEM_INDEFINITE_WAIT); > /* immediately unblocked as the semaphore is already posted */ > > /* Waits until the semaphore is posted */ > DosWaitEventSem (hevIpcInterrupt, (unsigned long) > SEM_INDEFINITE_WAIT); > > /* In Thread B */ > DosPostEventSem(hevIpcInterrupt); > > /* Close the semaphore */ > ulrc = DosCloseEventSem (hevIpcInterrupt); > > > > The following Linux example uses pthread conditional variable for synchronization between two threads, A and B: > > Listing 7. Linux condition variable > > pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; > pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; > > struct timeval tvTimeNow; //Absolute current time > struct timezone tzTimeZone; //Timezone > struct timespec tsTimeOut; // Input for timedwait > > /* In Thread A */ > ... > pthread_mutex_lock(&mutex); > /* signal one thread to wake up */ > pthread_cond_signal(&condvar); > pthread_mutex_unlock(&mutex); > /* this signal is lost as no one is waiting */ > > > /* In Thread B */ > > pthread_mutex_lock(&mutex); > > pthread_cond_wait(&condvar, &mutex); > > pthread_mutex_unlock(&mutex); > > > /* Thread B blocks indefintely */ > > /* --------------------------------------------------------------------- > --------------------------------------------------------------------- */ > > /* One way of avoiding losing the signal is as follows */ > > > /* In Thread B - Lock the mutex early to avoid losing signal > */ > > > > pthread_mutex_lock (&mutex); > > > > /* Do work */ > > ....... > > /* This work may lead other threads to send signal to > thread B */ > > /* Thread A now tries to take the mutex lock > to send the signal but gets blocked */ > ... > pthread_mutex_lock(&mutex); > > > /* Thread B: Get the current time */ > > gettimeofday (&tvTimeNow, &tzTimeZone); > > /* Calculate the absolute end time - 10 seconds wait */ > > tsTimeOut.tv_sec = tvTimeNow.tv_sec + 10 ; > > /* Thread B waits for the specified time for the signal to be > posted */ > > pthread_cond_timedwait (&condvar, &mutex, &tsTimeOut ); > /* Thread A now gets the lock and can > signal thread B to wake up */ > pthread_cond_signal(&condvar */ > pthread_mutex_unlock(&mutex); > ... /* Thread B > unblocks upon receipt of signal */ > > pthread_mutex_unlock (&mutex); > > > > The next example uses POSIX semaphores to implement synchronization between threads A and B: > > Listing 8. Linux POSIX semaphore > > sem_t sem; /* semaphore object */ > int irc; /* return code */ > > /* Initialize the semaphore - count is set to 1*/ > irc = sem_init (sem, 0,1); > ... > > /* In Thread A */ > > /* Wait for event to be posted */ > > sem_wait (&sem); > > /* Unblocks immediately as semaphore initial count was set to 1 */ > > ....... > > /* Wait again for event to be posted */ > > sem_wait (&sem); > > /* Blocks till event is posted */ > > /* In Thread B */ > /* Post the semaphore */ > ... > irc = sem_post (&sem); > > /* Destroy the semaphore */ > irc = sem_destroy(&sem); > > > > >
__, _, __, _,_ _, _
|_ / \ |_) | | |\/|
| \ / | \ | | | |
~ ~ ~ ~ `~' ~ ~
Programmed by
Dmitri Maximovich
,
Dmitry I. Platonoff
,
Eugen Kuleshov
.
25.09.99 (c) 1999,
RU/2
. All rights reserved.
Rewritten by
Dmitry Ban
. All rights ignored.