信号量是一种用于并发环境同步手段的原语,分为无名信号量和有名信号量两种,前者只能用于线程间同步,而后者还可用于进程间同步。它包括创建、等待、挂出、取值和销毁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>
3
typedef struct
4

{
5
union
6
{
7
sem_t* proc_sem_;
8
sem_t thr_sem_;
9
};
10
char* name_;
11
} sema_t;
12
13
typedef void SECURITY_ATTRIBUTES;
14
15
#elif defined(_SYSV_SEM)
16
typedef struct
17

{
18
int id_;
19
char* name_;
20
}sema_t;
21
22
typedef void SECURITY_ATTRIBUTES;
23
24
#elif defined(_PTHREAD_SEM)
25
#include <pthread.h>
26
typedef struct
27

{
28
pthread_cond_t cond_;
29
pthread_mutex_t lock_;
30
int value_;
31
}sem_t;
32
33
typedef struct
34

{
35
union
{
36
sem_t* proc_sem_;
37
sem_t thr_sem_;
38
};
39
char* name_;
40
}sema_t;
41
42
typedef void SECURITY_ATTRIBUTES;
43
44
#elif defined(_WIN32_SEM)
45
#include <windows.h>
46
typedef HANDLE sema_t;
47
48
#else
49
#error Currently only support posix,system v,pthread and win32 semaphore.
50
#endif
51
52
int sema_init(sema_t* s,const char* name,unsigned int value,unsigned int max,SECURITY_ATTRIBUTES* sa);
53
54
int sema_wait(sema_t* s);
55
56
int sema_trywait(sema_t* s);
57
58
int sema_post(sema_t* s);
59
60
int sema_getvalue(sema_t*s,int* val);
61
62
int sema_destroy(sema_t* s);
实现
1
int 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
56
int 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
91
int 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
128
int 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
154
int 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
177
int 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
春秋十二月 阅读(2154)
评论(0) 编辑 收藏 引用 所属分类:
C/C++