Условные переменные с многопоточностью - PullRequest
0 голосов
/ 28 апреля 2018

Я работаю над проблемой столовых философов, когда русские философы по очереди думают и едят. Я хотел бы иметь версию этого, где философы будут есть в порядке их идентификатора: 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 текущим идентификатором потока, если нет, то поток будет ждать, пока pindex не сравняется с идентификатором. Затем поток может пойти, и когда мы закончим, мы увеличим pindex, сообщим, что поток завершен, и разблокируем мьютекс.

1 Ответ

0 голосов
/ 28 апреля 2018

Этот код иногда работает, а иногда нет. Во-первых, поскольку вы не предоставили полную программу, вот недостающие биты, которые я использовал для тестирования:

#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() в условной переменной следующего философа.

...