你不需要静态变量。你想每次都创建一个新对象(内存分配)semCreate
叫做。像这样,
static SEM *sem ={
.val=initVal
};
应该
SEM *sem = malloc(sizeof(SEM));
sem->val = initVal;
使用完信号量后,不要忘记释放它。这包括错误!
SEM *semCreate(int initVal){
SEM *sem = malloc(sizeof(SEM));
if (!sem)
goto Error1;
sem->val = initVal;
errno = pthread_mutex_init(&sem->m, NULL);
if (!errno)
goto Error2;
errno = pthread_cond_init(&sem->c, NULL);
if (!errno)
goto Error3;
return sem;
Error3:
pthread_mutex_destroy(&sem->m);
Error2:
free(buf);
Error1:
return NULL;
}
除此之外,您的代码还有多个问题。简而言之,P
是完全错误的。
-
P
可以打电话pthread_cond_signal
具有未锁定的互斥体。
-
P
可以在互斥体仍然锁定的情况下返回。
-
P
当它是非正数时,它会减少该值,而当它是正数时,它应该减少它。
还有一个问题是,两者P
and V
执行无意义甚至有害的错误处理。如果广播失败则跳过互斥体解锁?是的,我们不要那样做。
让我们从一个基本的解决方案开始,不考虑安全性或效率。
void V(SEM *sem) {
++sem->val;
}
void P(SEM *sem) {
// Wait for the semaphore to have a positive value.
while (sem->val < 1) {
// This is where another thread could change sem->val.
}
--sem->val;
}
现在,让我们通过互斥使其成为线程安全的。
void V(SEM *sem) {
pthread_mutex_lock(&sem->m);
++sem->val;
pthread_mutex_unlock(&sem->m);
}
void P(SEM *sem) {
pthread_mutex_lock(&sem->m);
// Wait for the semaphore to have a positive value.
while (sem->val < 1) {
pthread_mutex_unlock(&sem->m);
// This is where another thread could change sem->val.
pthread_mutex_lock(&sem->m);
}
--sem->val;
pthread_mutex_unlock(&sem->m);
}
但这是一个忙碌的等待。让我们使用条件变量来休眠,直到信号量发生变化。 (记住cond_wait
在进入时解锁提供的互斥体并在返回之前重新锁定它。)
void V(SEM *sem) {
pthread_mutex_lock(&sem->m);
++sem->val;
// Wake up a thread that's waiting, if any.
if (sem->val > 0)
pthread_cond_signal(&sem->c);
pthread_mutex_unlock(&sem->m);
}
void P(SEM *sem) {
pthread_mutex_lock(&sem->m);
// Wait for the semaphore to have a positive value.
while (sem->val < 1)
pthread_cond_wait(&sem->c, &sem->m);
--sem->val;
// Wake up a thread that's waiting, if any.
if (sem->val > 0)
pthread_cond_signal(&sem->c);
pthread_mutex_unlock(&sem->m);
}
Tada!
Notes:
- 打电话没有意义
pthread_cond_broadcast
因为一次只有一个线程可以修改信号量。通过同时拥有V
and P
call pthread_cond_signal
在适当的时候,我们会避免无缘无故地唤醒线程。
- 我们可以省略检查是否
pthread_mutex_lock
, pthread_mutex_unlock
and pthread_cond_signal
工作代码失败,因为这些仅因编码错误而失败。