我正在尝试使用互斥量而不是信号量因为我想要信号量行为而不是二进制(不计算)。 (也许你会注意到我正处于尝试模拟睡眠理发算法的早期阶段。)这是我的代码:
#include <stdio.h>
#include <pthread.h>
int main( int argc, char** argv ) {
int freeSeats = 6;
pthread_mutexattr_t mutexAttr;
pthread_mutex_t custWaiting, wrAccess, barberReady;
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&custWaiting, &mutexAttr);
pthread_mutex_init(&wrAccess, &mutexAttr);
pthread_mutex_init(&barberReady, &mutexAttr);
pthread_mutex_lock(&custWaiting);
pthread_mutex_lock(&custWaiting);
pthread_mutex_lock(&custWaiting);
fprintf(stdout, "got here\n\n");
return 0;
}
当我执行第一次时,它按预期运行(线程被阻塞,命令行在我的程序等待能够锁定时挂起)。当我杀死程序并再次运行它时,它会打印“到这里”,它不应该。为什么这只会在第二次(以及所有后续)尝试中失败,但不会在第一次尝试失败?
令人费解的是,如果我修改代码如下(只有init和lock行):
#include <stdio.h>
#include <pthread.h>
int main( int argc, char** argv ) {
int freeSeats = 6;
pthread_mutexattr_t mutexAttr;
pthread_mutex_t custWaiting, wrAccess, barberReady;
pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED);
int y = pthread_mutex_init(&custWaiting, &mutexAttr);
y = pthread_mutex_init(&wrAccess, &mutexAttr);
y = pthread_mutex_init(&barberReady, &mutexAttr);
int x = pthread_mutex_lock(&custWaiting);
x = pthread_mutex_lock(&custWaiting);
x = pthread_mutex_lock(&custWaiting);
fprintf(stdout, "got here\n\n");
return 0;
}
......然后它每次都有效。这是如此令人抓狂的原因是因为我无法检查pthread_mutex_whatever()上的错误代码,因为当我尝试捕获错误代码时不失败。如果我不打算使用它们,我不想将返回值分配给int
s。如您所见,我根本没有使用x
或y
;只需为其分配init
和lock
函数的返回值即可。那么为什么这会大大改变互斥体的行为呢?还是我错过了别的什么?我做错了什么?
答案 0 :(得分:4)
你应该通过调用:
来初始化你的mutexattrpthread_mutexattr_init(&mutexAttr);
并设置类型:
pthread_mutexattr_settype(amutexAttr, PTHREAD_MUTEX_NORMAL);
否则您的代码取决于堆栈内容,并且互斥锁可以是递归类型,这就是您看到随机行为的原因。如果将类型设置为PTHREAD_MUTEX_DEFAULT
,则行为未定义,而PTHREAD_MUTEX_NORMAL
会导致死锁
答案 1 :(得分:2)
您正在锁定同一个互斥锁三次,这是未定义的行为,除非您声明您的互斥锁是递归的。可能你想锁定三种不同的互斥锁。
未定义的行为意味着任何事情都可能发生,包括您在此处观察到的行为。
要设置互斥锁的属性,您必须使用pthread_mutexattr_settype
更改互斥锁属性的属性。基本上有两种类型可以增强默认行为PTHREAD_MUTEX_ERRORCHECK
和PTHREAD_MUTEX_RECURSIVE
。如果您尝试重新锁定,第一个将阻止,第二个可以用于多次锁定和解锁。
默认行为是保留此未定义,因为实施此类检查的成本很高。