Semaphores are a means of synchronization between different processes or different threads of a given process.
In POSIX, there is already a set of signal interfaces for synchronization between different threads in the same process. The interfaces are:
int sem_init(sem_t *sem, int pshared, unsigned int value);int sem_wait(sem_t *sem);int sem_trywait(sem_t *sem);int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);int sem_destroy(sem_t *sem);int sem_getvalue(sem_t *sem);
However, the main purpose of the POSIX standard to implement semaphores is to provide a way to synchronize processes. Note that the focus is to solve the problem between processes. However, semaphores can also be used for inter-thread synchronization.
Inter-Process Synchronization uses the famous semaphores (sem_open (), sem_close (), sem_unlink (), sem_wait (), sem_post (), sem_getvalue (), sem_trywait ())
Inter-thread synchronization is generally implemented through mutex locks and condition variables, but the specific situation depends on the application scenario.
The following describes how to implement signals through mutex locks and conditional variables. The code is relatively simple:
#ifndef __DL_SEMA_H__#define __DL_SEMA_H__#ifdef __cplusplus#if __cplusplusextern "C" {#endif#endiftypedef void* dl_sema_t;extern intdl_sema_create(dl_sema_t *pSema, unsigned int init_cnt);extern intdl_sema_destroy(dl_sema_t sema);extern intdl_sema_p(dl_sema_t sema, int timeout);extern intdl_sema_v(dl_sema_t sema);#ifdef __cplusplus#if __cplusplus}#endif#endif#endif /* __DL_SEMA_H__ */
#include <pthread.h>#include <stdlib.h>#include <sys/time.h> /* gettimeofday() */#include "dl_sema.h"#ifdef __cplusplus#if __cplusplusextern "C" {#endif#endif#define SEMA_MAGIC 0xF147258Fstruct sema_info{ unsigned int magic; int cnt; pthread_mutex_t mutex; pthread_cond_t cond;};/* abstime = millsec + the current time */void dl_gettime(struct timespec *abstime, int millsec){ long sec, nsec; struct timeval cur_time; gettimeofday(&cur_time, 0); nsec = cur_time.tv_usec * 1000; sec = cur_time.tv_sec; nsec += (millsec%1000)*1000000; abstime->tv_nsec = nsec % 1000000000; sec += millsec/1000; sec += nsec / 1000000000; abstime->tv_sec = sec;}/* create a semaphore with init_cnt */int dl_sema_create(dl_sema_t *pSema, unsigned int init_cnt){ struct sema_info *sema; if(!pSema) return -1; sema = malloc(sizeof(struct sema_info)); if(!sema) return -1; if(pthread_mutex_init(&(sema->mutex), 0) != 0){ free(sema); return -1; } if( pthread_cond_init(&(sema->cond), 0) != 0){ pthread_mutex_destroy(&(sema->mutex)); free(sema); return -1; } sema->cnt = init_cnt; sema->magic = SEMA_MAGIC; *pSema = sema; return 0;}int dl_sema_p(dl_sema_t sema, int timeout){ struct sema_info *psema = (struct sema_info*) sema; int ret = 0; if(!psema || (psema->magic != SEMA_MAGIC) ) return -1; pthread_mutex_lock(&(psema->mutex)); if(psema->cnt <= 0){ /* wait forever */ if(timeout == 0){ while(psema->cnt <= 0){ if((ret = pthread_cond_wait(&(psema->cond), &(psema->mutex))) != 0){ pthread_mutex_unlock(&(psema->mutex)); return ret; } } } else { struct timespec abs_time; dl_gettime(&abs_time, timeout); while(psema->cnt <= 0){ ret = pthread_cond_timedwait(&(psema->cond), &(psema->mutex), &abs_time); if(ret != 0){ pthread_mutex_unlock(&(psema->mutex)); return ret; } } } } psema->cnt--; pthread_mutex_unlock(&(psema->mutex)); return 0;}int dl_sema_v(dl_sema_t sema){ int ret = 0; struct sema_info* psema = (struct sema_info*)sema; if(!psema || (psema->magic != SEMA_MAGIC) ) return -1; pthread_mutex_lock(&(psema->mutex)); psema->cnt++; ret = pthread_cond_signal(&(psema->cond)); if(ret != 0){ psema->cnt--; /* roll back */ pthread_mutex_unlock(&(psema->mutex)); return ret; } pthread_mutex_unlock(&(psema->mutex)); return 0;}int dl_sema_destroy(dl_sema_t sema){ struct sema_info* psema = (struct sema_info*)sema; int ret = 0; if(!psema || (psema->magic != SEMA_MAGIC) ) return -1; psema->magic = 0; if((ret = pthread_mutex_destroy(&(psema->mutex))) != 0) return ret; if((ret = pthread_cond_destroy(&(psema->cond))) != 0) return ret; free(psema); return 0;}#ifdef __cplusplus#if __cplusplus}#endif#endif
// Simple test code: # include <stdio. h> # include <pthread. h> # include <stdlib. h> # include "dl_sema.h" Void * thread_1 (void * Arg) {int ret; dl_sema_t Sema = (dl_sema_t) ARG; ret = dl_sema_p (Sema, 3000 ); /* 3 s timeout */If (ret = 0) printf ("the semaphore come up! \ N "); dl_sema_destroy (SEMA); Return 0;} void * thread_2 (void * Arg) {dl_sema_t Sema = (dl_sema_t) ARG; dl_sema_v (SEMA ); printf ("OK !!!! \ N "); Return 0;} int main (INT argc, char ** argv) {pthread_t thid; dl_sema_t Sema; If (dl_sema_create (& Sema, 0 )) printf ("dl_sema_init failed. \ n "); pthread_create (& thid, 0, thread_1, SEMA); pthread_create (& thid, 0, thread_2, SEMA); sleep (5); Return 0 ;}