【问题标题】:Conditional Variables with multithreading多线程条件变量
【发布时间】:2018-10-08 18:43:38
【问题描述】:

我正在研究哲学家进餐问题,其中 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,发出线程完成的信号,并解锁互斥锁。

【问题讨论】:

  • @jxh,在另一种方法中,我在一个循环中创建 n 个线程并为每个线程分配循环值:0,1,2,3...(我还确保它是正确的值)。 pindex 不应该返回 0,而是应该循环遍历 id 值,从 0 开始到 1,然后是 2,3,4... 这就是我有 pindex++ 的原因。
  • @jxh 我做了另一个版本,涉及在每根筷子上使用互斥锁。但是现在我想模拟一个他们按顺序吃饭的问题。这意味着通常哲学家 1 和 2 共用一根筷子,但现在这无关紧要,因为哲学家 2 在 1 吃完之前不能吃东西。
  • @jxh 我在第一个函数putDownChopstick 中有pthread_cond_signal,这样我可以在线程完成进食后发出信号。
  • “据我所知我做得对”,真的吗?据您所知,看起来更像是您的代码死锁。我们不知道,因为您没有提供完整的代码。

标签: c multithreading mutex condition-variable


【解决方案1】:

此代码有时有效,有时无效。首先,由于您没有提供完整的程序,以下是我用于测试目的的缺失部分:

#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);

这个调用只会唤醒一个线程。但是,哪个线程由操作系统决定。因此,如果它没有唤醒应该唤醒的哲学家,则不会唤醒其他哲学家。

一个简单的解决方法是唤醒所有等待的线程,而不仅仅是一个。不匹配的哲学家会回去等待,下一个应该去的哲学家会去。

 pthread_cond_broadcast(&cond);

但是,由于每个线程都知道应该唤醒哪个哲学家,因此您可以更改解决方案以允许这种情况发生。一种方法是为每个哲学家实现一个单独的条件变量,并在下一个哲学家的条件变量上使用pthread_cond_signal()

【讨论】:

  • 哇,我已经为此头疼了,看了两天的教程/网站!我承认问题是从未想到过的信号。
  • 我想知道您是否可以回答有关互斥锁的问题?如果有 n 个哲学家,那么互斥体将代表 n 个叉子。使用mutex[n] 的数组更好还是我可以简单地使用两个互斥锁(left_fork 互斥锁和 right_fork 互斥锁并在线程之间共享它们)。
  • 我的系统运行良好。我一遍又一遍地手动重试你的程序,从未死锁。因此,我在脚本中运行了 1000 次,结果出现了死锁。注意到pindex 确实具有正确的值以供等待线程之一继续,这意味着它没有被唤醒。
  • 那么,你如何表示一位哲学家的左叉是另一位哲学家的右叉?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-27
  • 1970-01-01
  • 2022-01-03
  • 2018-09-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多