信号量是一种用于并发环境同步手段的原语,分为无名信号量和有名信号量两种,前者只能用于线程间同步,而后者还可用于进程间同步。它包括创建、等待、挂出、取值和销毁5种基本操作。与互斥锁不同的是:
● 信号量拥有一个计数值,表示可用的资源数量,仅当该值为0或1时,则相当于互斥锁。
● 信号量是条件式加锁,即仅当计数值不大于0时才会锁住当前线程或进程,而互斥锁则是无条件。
● 信号量的加锁和解锁不必是同一线程或进程,而互斥锁则必须是同一个。
● 任何线程或进程都可以挂出一个信号,即使当前没有线程或进程正在等待该信号值变成正数,而互斥锁在没有加锁后解锁则会发生错误。
本文展示了基于Posix、PThread、SystemV和Win32四种平台的封装实现。
接口
所有信号量操作,成功返回0,失败返回-1,对应的错误码,win32可调用getlasterror获取,其它平台则是errno。对于win32平台的wait和trywait操作,废弃返回1,超时返回2;因当前没有获取信号值的API,sema_getvalue操作简单地返回-1。
1#ifdef _POSIX_SEM
2#include <semaphore.h>
3typedef struct
4{
5 union
6 {
7 sem_t* proc_sem_;
8 sem_t thr_sem_;
9 };
10 char* name_;
11} sema_t;
12
13typedef void SECURITY_ATTRIBUTES;
14
15#elif defined(_SYSV_SEM)
16typedef struct
17{
18 int id_;
19 char* name_;
20}sema_t;
21
22typedef void SECURITY_ATTRIBUTES;
23
24#elif defined(_PTHREAD_SEM)
25#include <pthread.h>
26typedef struct
27{
28 pthread_cond_t cond_;
29 pthread_mutex_t lock_;
30 int value_;
31}sem_t;
32
33typedef struct
34{
35 union {
36 sem_t* proc_sem_;
37 sem_t thr_sem_;
38 };
39 char* name_;
40}sema_t;
41
42typedef void SECURITY_ATTRIBUTES;
43
44#elif defined(_WIN32_SEM)
45#include <windows.h>
46typedef HANDLE sema_t;
47
48#else
49#error Currently only support posix,system v,pthread and win32 semaphore.
50#endif
51
52int sema_init(sema_t* s,const char* name,unsigned int value,unsigned int max,SECURITY_ATTRIBUTES* sa);
53
54int sema_wait(sema_t* s);
55
56int sema_trywait(sema_t* s);
57
58int sema_post(sema_t* s);
59
60int sema_getvalue(sema_t*s,int* val);
61
62int sema_destroy(sema_t* s);
实现
1int sema_init(sema_t* s,const char* name,unsigned int value,unsigned int max,SECURITY_ATTRIBUTES* sa)
2{
3#ifdef _POSIX_SEM
4 if(name){
5 s->name_ = strdup(name);
6 if(0==s->name_)
7 return -1;
8 s->proc_sem_ = sem_open(name,O_CREAT,DEFAULT_FILE_PERMS,value);
9 if(SEM_FAILED==s->proc_sem_) {
10 free(s->name_);
11 return -1;
12 }
13 }else{
14 if(-1==sem_init(&s->thr_sem_,0,value))
15 return -1;
16 s->name_ = 0;
17 }
18 return 0;
19#elif defined(_SYSV_SEM)
20 if(name){
21 s->name_ = strdup(name);
22 if(0==s->name_)
23 return -1;
24 if(-1==__sysv_sem_open(&s->id_,name,value)){
25 free(s->name_);
26 return -1;
27 }
28 return 0;
29 }else{
30 if(-1==__sysv_init(&s->id_,value))
31 return -1;
32 s->name_ = 0;
33 }
34 return 0;
35#elif defined(_PTHREAD_SEM)
36 if(name){
37 s->name_ = strdup(name);
38 if(0==s->name_)
39 return -1;
40 s->proc_sem_ = __pthread_sem_open(name,value);
41 if(0==s->proc_sem_){
42 free(s->name_);
43 return -1;
44 }
45 }else{
46 if(-1==__pthread_init(&s->thr_sem_,value))
47 return -1;
48 s->name_ = 0;
49 }
50 return 0;
51#else
52 return (*s = CreateSemaphoreA(sa,value,max,name)) ? 0 : -1;
53#endif
54}
55
56int sema_wait(sema_t* s)
57{
58#ifdef _POSIX_SEM
59 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
60 return sem_wait(sem);
61#elif defined(_SYSV_SEM)
62 struct sembuf op;
63 int ret;
64 op.sem_num = 0;
65 op.sem_op = -1;
66 op.sem_flg = 0;
67 return semop(s->id_, &op, 1);
68#elif defined(_PTHREAD_SEM)
69 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
70
71 int ret = pthread_mutex_lock(&sem->lock_);
72 if(ret) {
73 errno = ret; return -1;
74 }
75 while(0==sem->value_)
76 pthread_cond_wait(&sem->cond_,&sem->lock_);
77 --sem->value_;
78 pthread_mutex_unlock(&sem->lock_);
79
80 return 0;
81#else
82 switch (WaitForSingleObject(*s, INFINITE))
83 {
84 case WAIT_OBJECT_0: return 0;
85 case WAIT_ABANDONED: return 1;
86 default: return -1;
87 }
88#endif
89}
90
91int sema_trywait(sema_t* s)
92{
93#ifdef _POSIX_SEM
94 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
95 return sem_trywait(sem);
96#elif defined(_SYSV_SEM)
97 struct sembuf op;
98 op.sem_num = 0;
99 op.sem_op = -1;
100 op.sem_flg = IPC_NOWAIT;
101 return semop(s->id_, &op, 1);
102#elif defined(_PTHREAD_SEM)
103 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
104
105 int ret = pthread_mutex_lock(&sem->lock_);
106 if(ret) {
107 errno = ret; return -1;
108 }
109 if(0==sem->value_){
110 ret = -1; errno = EAGAIN;
111 }else {
112 ret = 0; --sem->value_;
113 }
114 pthread_mutex_unlock(&sem->lock_);
115
116 return ret;
117#else
118 switch (WaitForSingleObject (*s, 0))
119 {
120 case WAIT_OBJECT_0: return 0;
121 case WAIT_ABANDONED: return 1;
122 case WAIT_TIMEOUT: return 2;
123 default: return -1;
124 }
125#endif
126}
127
128int sema_post(sema_t* s)
129{
130#ifdef _POSIX_SEM
131 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
132 return sem_post(sem);
133#elif defined(_SYSV_SEM)
134 struct sembuf op;
135 op.sem_num = 0;
136 op.sem_op = 1;
137 op.sem_flg = 0;
138 return semop(s->id_, &op, 1);
139#elif defined(_PTHREAD_SEM)
140 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
141
142 pthread_mutex_lock(&sem->lock_);
143 if(0==sem->value_)
144 pthread_cond_signal(&sem->cond_);
145 ++sem->value_;
146 pthread_mutex_unlock(&sem->lock_);
147
148 return 0;
149#else
150 return ReleaseSemaphore(*s,1,0) ? 0 : -1;
151#endif
152}
153
154int sema_getvalue(sema_t* s,int* val)
155{
156#ifdef _POSIX_SEM
157 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
158 return sem_getvalue(sem,val);
159#elif defined(_SYSV_SEM)
160 int tmp = semctl(s->id_,0,GETVAL);
161 if(tmp < 0) return -1;
162 *val = tmp;
163 return 0;
164#elif defined(_PTHREAD_SEM)
165 sem_t* sem = s->name_ ? s->proc_sem_ : &s->thr_sem_;
166 int ret = pthread_mutex_lock(&sem->lock_);
167 if(ret){
168 errno = ret; return -1;
169 }
170 *val = sem->value_;
171 pthread_mutex_unlock(&sem->lock_);
172#else
173 return -1;
174#endif
175}
176
177int sema_destroy(sema_t* s)
178{
179#ifdef _POSIX_SEM
180 if(s->name_){
181 sem_unlink(s->name_);
182 free(s->name_);
183 if(-1==sem_close(s->proc_sem_))
184 return -1;
185 }else{
186 if(-1==sem_destroy(&s->thr_sem_))
187 return -1;
188 }
189 return 0;
190#elif defined(_SYSV_SEM)
191 return semctl(s->id_,0,IPC_RMID);
192#elif defined(_PTHREAD_SEM)
193 if(s->name_) {
194 sem_t* sem = s->proc_sem_;
195
196 unlink(s->name_);
197 free(s->name_);
198 pthread_mutex_destroy(&sem->lock_);
199 pthread_cond_destroy(&sem->cond_);
200
201 return munmap(sem,sizeof(sem_t));
202 }else {
203 pthread_mutex_destroy(&s->thr_sem_.lock_);
204 pthread_cond_destroy(&s->thr_sem_.cond_);
205 }
206 return 0;
207#else
208 return CloseHandle(*s) ? 0 : -1;
209#endif
210}
posted on 2012-07-20 10:52
春秋十二月 阅读(2127)
评论(0) 编辑 收藏 引用 所属分类:
C/C++