多线程条件变量
Conditional Variables with multithreading
我正在研究哲学家用餐问题,其中 n 个哲学家轮流思考和吃饭。我想要一个这样的版本,哲学家将按照他们的 id 的顺序进餐:0,1,2,3,4...,但我的线程一直被阻塞。我的线程从调用 PhilosopherThread
().
开始
void putDownChopsticks(int threadIndex){
//finished eating
pindex++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void pickUpChopsticks(int threadIndex){
pthread_mutex_lock(&lock);
while(pindex != threadIndex){
pthread_cond_wait(&cond, &lock);
}
//lets go eat
}
void eating(){
//put thread to sleep
}
void thinking(){
//put thread to sleep
}
void* PhilosopherThread(void *x){
int *index = x;
thinking(); //just puts thread to sleep to simulate thinking
pickUpChopsticks(*index);
eating(); //just puts thread to sleep to simulate eating
putDownChopsticks(*index);
return NULL;
}
我在试图让哲学家们井然有序时遇到了一些麻烦。我只能在线程被阻塞之前让前 2 个线程吃掉。
编辑: 据我所知,我这样做是对的。我首先锁定互斥锁,然后我检查 pindex 是否是当前线程 ID,如果不是,线程将等待直到 pindex 等于 id。然后线程可以去吃,一旦完成,我们增加 pindex,表示线程已完成,并解锁互斥量。
此代码有时有效,有时无效。首先,由于您没有提供完整的程序,这里是我用于测试目的的缺失部分:
#include <stdlib.h>
#include <pthread.h>
static pthread_cond_t cond;
static pthread_mutex_t lock;
static pindex;
/* ... your code ... */
int main () {
int id[5], i;
pthread_t tid[5];
for (i = 0; i < 5; ++i) {
id[i] = i;
pthread_create(tid+i, 0, PhilosopherThread, id+i);
}
for (i = 0; i < 5; ++i) pthread_join(tid[i], 0);
exit(0);
}
要注意的关键是你如何唤醒下一位哲学家:
pthread_cond_signal(&cond);
这个调用只会唤醒一个线程。但是,哪个线程由 OS 自行决定。因此,如果它没有恰好唤醒应该唤醒的哲学家,则没有其他哲学家被唤醒。
一个简单的解决方法是唤醒所有等待的线程而不是一个。不匹配的哲学家会回去等待,下一个应该去的会去。
pthread_cond_broadcast(&cond);
但是,由于每个线程都知道哪个哲学家应该醒来,您可以更改您的解决方案以实现这一点。一种方法是为每个哲学家实现一个单独的条件变量,并在下一个哲学家的条件变量上使用 pthread_cond_signal()
。
我正在研究哲学家用餐问题,其中 n 个哲学家轮流思考和吃饭。我想要一个这样的版本,哲学家将按照他们的 id 的顺序进餐:0,1,2,3,4...,但我的线程一直被阻塞。我的线程从调用 PhilosopherThread
().
void putDownChopsticks(int threadIndex){
//finished eating
pindex++;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
}
void pickUpChopsticks(int threadIndex){
pthread_mutex_lock(&lock);
while(pindex != threadIndex){
pthread_cond_wait(&cond, &lock);
}
//lets go eat
}
void eating(){
//put thread to sleep
}
void thinking(){
//put thread to sleep
}
void* PhilosopherThread(void *x){
int *index = x;
thinking(); //just puts thread to sleep to simulate thinking
pickUpChopsticks(*index);
eating(); //just puts thread to sleep to simulate eating
putDownChopsticks(*index);
return NULL;
}
我在试图让哲学家们井然有序时遇到了一些麻烦。我只能在线程被阻塞之前让前 2 个线程吃掉。
编辑: 据我所知,我这样做是对的。我首先锁定互斥锁,然后我检查 pindex 是否是当前线程 ID,如果不是,线程将等待直到 pindex 等于 id。然后线程可以去吃,一旦完成,我们增加 pindex,表示线程已完成,并解锁互斥量。
此代码有时有效,有时无效。首先,由于您没有提供完整的程序,这里是我用于测试目的的缺失部分:
#include <stdlib.h>
#include <pthread.h>
static pthread_cond_t cond;
static pthread_mutex_t lock;
static pindex;
/* ... your code ... */
int main () {
int id[5], i;
pthread_t tid[5];
for (i = 0; i < 5; ++i) {
id[i] = i;
pthread_create(tid+i, 0, PhilosopherThread, id+i);
}
for (i = 0; i < 5; ++i) pthread_join(tid[i], 0);
exit(0);
}
要注意的关键是你如何唤醒下一位哲学家:
pthread_cond_signal(&cond);
这个调用只会唤醒一个线程。但是,哪个线程由 OS 自行决定。因此,如果它没有恰好唤醒应该唤醒的哲学家,则没有其他哲学家被唤醒。
一个简单的解决方法是唤醒所有等待的线程而不是一个。不匹配的哲学家会回去等待,下一个应该去的会去。
pthread_cond_broadcast(&cond);
但是,由于每个线程都知道哪个哲学家应该醒来,您可以更改您的解决方案以实现这一点。一种方法是为每个哲学家实现一个单独的条件变量,并在下一个哲学家的条件变量上使用 pthread_cond_signal()
。