ubi*_*con 0 c deadlock pthreads
该计划正在努力实现的目标:
该程序应该同步"访客"和"汽车"的几个线程.游客们随意漫步,直到他们决定乘车.如果他们是第一次乘坐汽车并且有车可以乘坐,那么他们必须等到他们第一次排队或者车回来.如果没有排队的游客,车辆会等待,直到游客想要乘车.
更多背景信息:
我重拍使用条件变量作为接受的答案建议我的线程同步程序在这里.我知道我在正确的轨道上,但由于某些原因,我的程序仍然陷入僵局,对于我的生活,我无法弄清楚为什么.除非我给你代码,否则我不知道你怎么能帮助我,所以这里是:
问题:
1.)一小段后死锁
2.)有时候一位游客首先排队买车,但从不上车.
解决方案:
我的代码中有太多的错误......我认为,因为我会修复一个,我经常(不经意间)引入另一个.我一直在删除程序的功能,直到我消除了所有的错误,然后以一种不会使我的程序死锁的方式逐个构建功能.谢谢大家的建议.
首先,xscott是正确的,你错误地使用互斥锁.如果它似乎在短时间内工作并不重要,它仍然是错误的,并且由于纯粹的机会可能只是出现在工作中.
我认为最好的方法是从最初的原则构建设计,而不是逐行完成代码.我会描述我认为你喜欢的基本算法:
visitor {
sleep
join end of visitor queue
wait until at head of visitor queue
wait until there is a car free
remove car from car queue
remove self from visitor queue
occupy car
wait until not in car anymore
}
car {
join end of car queue
wait until occupied
sleep
eject visitor from car
}
Run Code Online (Sandbox Code Playgroud)
请注意,我没有明确标记唤醒点 - 只是等待.这是最好的方法 - 找出你需要等待某些东西改变状态的地方,然后只需要在状态发生变化时放入唤醒(发出条件变量信号).
下一步是确定需要由互斥锁保护的主要共享数据.我知道了:
- The visitor queue;
- The car queue;
- The status of each car.
Run Code Online (Sandbox Code Playgroud)
因此,最细粒度的方法是为访问者队列设置一个互斥锁(我们可以使用你的v_mutex),一个用于汽车队列(c_mutex),一个用于每个汽车(sc[CARS]).或者,您可以c_mutex用来保护汽车队列和每辆汽车的状态; 或者只是v_mutex用来保护一切.但是为了学习,我们将采用更复杂的方法.
下一步是确定条件变量有用的等待点.因为wait until at head of visitor queue,您的每个访客条件变量(v_cond)将没有问题; 因为wait until there is a car free它最容易添加另一个条件变量(v_car_cond).对于wait until occupied每车状况,变量c_cond是合适的.对于wait until not in car anymore其中一种v_cond或c_cond可以使用,因为此时汽车和访客之间存在一对一的关系.没有必要v_cond2.
我们现在可以根据pthreads原语重写上面的伪代码.在大多数情况下,这非常接近你已经拥有的 - 所以你肯定是在正确的轨道上.首先是访客:
/* join end of visitor queue */
pthread_mutex_lock(&v_mutex);
v_line[v_id] = set_visitor_place_in_line();
printf("Visitor %d is %d in line for a ride\n", v_id, v_line[v_id]);
pthread_mutex_unlock(&v_mutex);
/* wait until first in line */
pthread_mutex_lock(&v_mutex);
while (v_line[v_id] != 1) {
pthread_cond_wait(&v_cond[v_id], &v_mutex);
}
pthread_mutex_unlock(&v_mutex);
/* wait until there is a car free */
pthread_mutex_lock(&c_mutex);
while ((car = get_next_car()) == CARS) {
pthread_cond_wait(&v_car_cond, &c_mutex);
}
pthread_mutex_unlock(&c_mutex);
/* remove car from car queue */
pthread_mutex_lock(&c_mutex);
move_car_line();
/* NOTE: We do not need to signal v_car_cond here, because only the first
* visitor in line can be waiting there, and we are still the first visitor
* in line at this point. */
pthread_mutex_unlock(&c_mutex);
/* remove self from visitor queue */
pthread_mutex_lock(&v_mutex);
move_passenger_line();
next_v = get_next_passenger();
if (next_v < VISITORS)
pthread_cond_signal(&v_cond[next_v]);
pthread_mutex_unlock(&v_mutex);
/* occupy car */
pthread_mutex_lock(&sc[car]);
c_state[car] = v_id;
pthread_cond_signal(&c_cond[car]);
pthread_mutex_unlock(&sc[car]);
/* wait until not in car anymore */
pthread_mutex_lock(&sc[car]);
while(c_state[car] == v_id) {
pthread_cond_wait(&v_cond[v_id], &sc[car]);
}
pthread_mutex_unlock(&sc[car]);
Run Code Online (Sandbox Code Playgroud)
二,车:
/* join end of car queue */
pthread_mutex_lock(&c_mutex);
c_line[c_id] = set_car_place_in_line();
if (c_line[c_id] == 1)
pthread_cond_signal(&v_car_cond);
pthread_mutex_unlock(&c_mutex);
/* wait until occupied */
pthread_mutex_lock(&sc[c_id]);
while ((v_id = c_state[c_id]) == VISITORS) {
pthread_cond_wait(&c_cond[c_id], &sc[c_id]);
}
pthread_mutex_unlock(&sc[c_id]);
/* visitor is on car ride for random amount of time */
sleep(rand()%5);
/* eject visitor from car */
pthread_mutex_lock(&sc[c_id]);
c_state[c_id] = VISITORS;
pthread_cond_signal(&v_cond[v_id]);
pthread_mutex_unlock(&sc[c_id]);
Run Code Online (Sandbox Code Playgroud)
上述能够简化-只要有一个pthread_mutex_unlock()由一个紧接着pthread_mutex_lock()相同的互斥的,解锁/锁定一对可以被移除.
PS:
你不应该担心你的汽车以"错误的顺序"加入汽车排队 - 他们会因为无论如何在公园周围徘徊而出现故障.如果您真的关心这一点,请在启动任何汽车线程之前将汽车放入主线程的队列中,并更改汽车代码,以便在主循环结束时将其重新添加到队列中.
使用这种方法的整体代码,省略了你的全局变量和辅助函数,这很好,如下所示:
pthread_mutex_t c_mutex = PTHREAD_MUTEX_INITIALIZER; /* mutex protecting c_line and cars_out */
pthread_mutex_t v_mutex = PTHREAD_MUTEX_INITIALIZER; /* mutex protecting v_line */
pthread_cond_t c_cond[CARS]; /* condition variables for waiting for c_state[i] to change from VISITORS to another value */
pthread_cond_t v_cond[VISITORS]; /* condition variables for visitor waiting to be first in line or ejected from a car */
pthread_cond_t v_car_cond = PTHREAD_COND_INITIALIZER; /* Condition variable for a visitor first in line, but waiting for a car. */
pthread_mutex_t sc[CARS]; /* one mutex per car, sc[i] protects c_state[i] */
int main(){
int i;
void *status;
pthread_t c[CARS];
pthread_t v[VISITORS];
srand(time(NULL));
printf("Jurassic Park is open, cars are being prepped for passengers\n");
for (i = 0; i < CARS; i++){
pthread_mutex_init(&sc[i], NULL);
pthread_cond_init(&c_cond[i], NULL);
}
for (i = 0; i < VISITORS; i++){
pthread_cond_init(&v_cond[i], NULL);
}
for (i = 0; i < CARS; i++){
c_state[i] = VISITORS;
pthread_create(&c[i], NULL, car, (void *)i);
}
for (i = 0; i < VISITORS; i++){
pthread_create(&v[i], NULL, visitor, (void *)i);
}
for (i = 0; i < VISITORS; i++){
pthread_join(v[i], &status);
}
museum_empty++;
printf("All visitors have left Jurassic Park\n");
for (i = 0; i < CARS; i++){
pthread_mutex_lock(&sc[i]);
c_state[i] = -1;
pthread_cond_signal(&c_cond[i]);
pthread_mutex_unlock(&sc[i]);
}
for (i = 0; i < CARS; i++){
pthread_join(c[i], &status);
}
printf("Jurrasic Park is closed, all cars have been parked\n");
pthread_exit(NULL);
return 0;
}
void *car(void *i)
{
int c_id = (int) i;
int v_id;
while (museum_empty != 1) {
/* join end of car queue */
pthread_mutex_lock(&c_mutex);
c_line[c_id] = set_car_place_in_line();
if (c_line[c_id] == 1)
pthread_cond_signal(&v_car_cond);
printf("Car %d is ready for a passenger and is %d in line %d of %d cars are out\n", c_id, c_line[c_id], cars_out, CARS);
pthread_mutex_unlock(&c_mutex);
/* wait until occupied */
pthread_mutex_lock(&sc[c_id]);
while ((v_id = c_state[c_id]) == VISITORS) {
pthread_cond_wait(&c_cond[c_id], &sc[c_id]);
}
pthread_mutex_unlock(&sc[c_id]);
if(museum_empty == 1){
break;
}
pthread_mutex_lock(&c_mutex);
cars_out++;
printf("Visitor %d is riding in car %d %d of %d cars are out --\n", v_id, c_id, cars_out, CARS);
pthread_mutex_unlock(&c_mutex);
/* visitor is on car ride for random amount of time */
sleep(rand()%5);
printf("Visitor %d is done riding in car %d\n", v_id, c_id);
/* eject visitor from car */
pthread_mutex_lock(&sc[c_id]);
c_state[c_id] = VISITORS;
pthread_cond_signal(&v_cond[v_id]);
pthread_mutex_unlock(&sc[c_id]);
pthread_mutex_lock(&c_mutex);
cars_out--;
pthread_mutex_unlock(&c_mutex);
}
return NULL;
}
void *visitor(void *i)
{
int v_id = (int) i;
int next_v;
int j = 0;
int car;
while (j < RIDES) {
if (j == 0) {
printf("Visitor %d entered museum and is wandering around\n", v_id);
} else {
printf("Visitor %d got back from ride and is wandering around\n", v_id);
}
sleep(rand()%3); /* visitor is wandering */
/* join end of visitor queue */
pthread_mutex_lock(&v_mutex);
v_line[v_id] = set_visitor_place_in_line();
printf("Visitor %d is %d in line for a ride\n", v_id, v_line[v_id]);
/* wait until first in line */
while (v_line[v_id] != 1) {
pthread_cond_wait(&v_cond[v_id], &v_mutex);
}
pthread_mutex_unlock(&v_mutex);
/* wait until there is a car free */
pthread_mutex_lock(&c_mutex);
while ((car = get_next_car()) == CARS) {
pthread_cond_wait(&v_car_cond, &c_mutex);
}
/* remove car from car queue */
move_car_line();
pthread_mutex_unlock(&c_mutex);
/* remove self from visitor queue */
pthread_mutex_lock(&v_mutex);
move_passenger_line();
next_v = get_next_passenger();
if (next_v < VISITORS)
pthread_cond_signal(&v_cond[next_v]);
pthread_mutex_unlock(&v_mutex);
/* occupy car */
pthread_mutex_lock(&sc[car]);
c_state[car] = v_id;
pthread_cond_signal(&c_cond[car]);
/* wait until not in car anymore */
/* NOTE: This test must be against v_id and *not* VISITORS, because the car could have been
* subsequently occupied by another visitor before we are woken. */
while(c_state[car] == v_id) {
pthread_cond_wait(&v_cond[v_id], &sc[car]);
}
pthread_mutex_unlock(&sc[car]);
j++;
}
printf("Visitor %d leaving museum.\n", v_id);
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
我希望这是有帮助的...