使用 pthread、互斥锁和条件变量解决哲学家就餐问题
Posted
技术标签:
【中文标题】使用 pthread、互斥锁和条件变量解决哲学家就餐问题【英文标题】:Solve Dining Philosophers Problem Using pthreads, mutex locks, and condition variables 【发布时间】:2020-07-29 23:51:53 【问题描述】:我正在尝试使用 pthread、互斥锁和条件变量在 C 中实现哲学家就餐问题。
它需要一个命令行参数来指定程序应该运行多长时间。我必须使用 sleep 功能来完成此操作。 每位哲学家最多可以吃 10 顿饭。一旦他们吃完 10 顿饭,pthread 就应该终止。 在设定的时间结束时,pthreads 需要终止,并且应该打印每个哲学家吃的饭数。我的输出有一些问题:
-
使主函数休眠在命令行中输入的秒数似乎不会使输出有所不同。
大多数哲学家都在为程序的大多数执行而挨饿。
当我打印出哲学家正在思考或吃饭时,会出现“哲学家 5”,即使应该只有 0-4 位哲学家。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
//Function declarations
void *pickup_forks(void * philosopher_number);
void *return_forks(void * philosopher_number);
void test(int philosopher_number);
int left_neighbor(int philosopher_number);
int right_neighbor(int philosopher_number);
double think_eat_time(void);
void think(double think_time);
void eat(double eat_time);
//Constants to be used in the program.
#define PHILOSOPHER_NUM 5
#define MAX_MEALS 10
#define MAX_THINK_EAT_SEC 3
//States of philosophers.
enum THINKING, HUNGRY, EATING state[PHILOSOPHER_NUM];
//Array to hold the thread identifiers.
pthread_t philos_thread_ids[PHILOSOPHER_NUM];
//Mutex lock.
pthread_mutex_t mutex;
//Condition variables.
pthread_cond_t cond_vars[PHILOSOPHER_NUM];
//Array to hold the number of meals eaten for each philosopher.
int meals_eaten[PHILOSOPHER_NUM];
int main(int argc, char *argv[])
//Ensure correct number of command line arguments.
if(argc != 2)
printf("Please ensure that the command line argument 'run_time' is passed.\n");
else
//Set command line argument value to variable run_time;
double run_time = atof(argv[1]);
//Initialize arrays.
int i;
for(i = 0; i < PHILOSOPHER_NUM; i++)
state[i] = THINKING;
pthread_cond_init(&cond_vars[i], NULL);
meals_eaten[i] = 0;
//Initialize the mutex lock.
pthread_mutex_init(&mutex, NULL);
//Join the threads.
for(i = 0; i < PHILOSOPHER_NUM; i++)
pthread_join(philos_thread_ids[i], NULL);
//Create threads for the philosophers.
for(i = 0; i < PHILOSOPHER_NUM; i++)
pthread_create(&philos_thread_ids[i], NULL, pickup_forks, (void *)&i);
sleep(run_time);
for(i = 0; i < PHILOSOPHER_NUM; i++)
pthread_cancel(philos_thread_ids[i]);
//Print the number of meals that each philosopher ate.
for(i = 0; i < PHILOSOPHER_NUM; i++)
printf("Philosopher %d: %d meals\n", i, meals_eaten[i]);
return 0;
void *pickup_forks(void * philosopher_number)
int loop_iterations = 0;
int pnum = *(int *)philosopher_number;
while(meals_eaten[pnum] < MAX_MEALS)
printf("Philosoper %d is thinking.\n", pnum);
think(think_eat_time());
pthread_mutex_lock(&mutex);
state[pnum] = HUNGRY;
test(pnum);
while(state[pnum] != EATING)
pthread_cond_wait(&cond_vars[pnum], &mutex);
pthread_mutex_unlock(&mutex);
(meals_eaten[pnum])++;
printf("Philosoper %d is eating meal %d.\n", pnum, meals_eaten[pnum]);
eat(think_eat_time());
return_forks((philosopher_number));
loop_iterations++;
void *return_forks(void * philosopher_number)
pthread_mutex_lock(&mutex);
int pnum = *(int *)philosopher_number;
state[pnum] = THINKING;
test(left_neighbor(pnum));
test(right_neighbor(pnum));
pthread_mutex_unlock(&mutex);
int left_neighbor(int philosopher_number)
return ((philosopher_number + (PHILOSOPHER_NUM - 1)) % 5);
int right_neighbor(int philosopher_number)
return ((philosopher_number + 1) % 5);
void test(int philosopher_number)
if((state[left_neighbor(philosopher_number)] != EATING) &&
(state[philosopher_number] == HUNGRY) &&
(state[right_neighbor(philosopher_number)] != EATING))
state[philosopher_number] = EATING;
pthread_cond_signal(&cond_vars[philosopher_number]);
double think_eat_time(void)
return ((double)rand() * (MAX_THINK_EAT_SEC - 1)) / (double)RAND_MAX + 1;
void think(double think_time)
sleep(think_time);
void eat(double eat_time)
sleep(eat_time);
这是使用 10 秒的输出:
~$ gcc dining_philos.c -o dp -lpthread
~$ ./dp 10
Philosoper 1 is thinking.
Philosoper 2 is thinking.
Philosoper 3 is thinking.
Philosoper 4 is thinking.
Philosoper 5 is thinking.
Philosoper 2 is eating meal 1.
Philosoper 4 is eating meal 1.
Philosoper 2 is thinking.
Philosoper 4 is thinking.
Philosoper 2 is eating meal 2.
Philosoper 4 is eating meal 4.
Philosoper 4 is thinking.
Philosoper 2 is thinking.
Philosoper 2 is eating meal 3.
Philosoper 4 is eating meal 5.
Philosoper 2 is thinking.
Philosoper 4 is thinking.
Philosopher 0: 2 meals
Philosopher 1: 0 meals
Philosopher 2: 3 meals
Philosopher 3: 0 meals
Philosopher 4: 5 meals
我将不胜感激。谢谢!
【问题讨论】:
【参考方案1】:pthread_create 传递一个指针作为其最后一个参数。该指针必须在线程运行时有效,而不仅仅是在创建时有效。您正在使用指向循环变量 i 的指针,该指针已消失。
也不确定您为什么在 pthread_create 之前调用 pthread_join,但我预计它会返回错误(您没有检查)。
【讨论】:
好的。我创建了另一个包含哲学家编号的数组,并在 pthread_create 中为哲学家 i 传递了该数组的第 i 个索引。这似乎成功了。谢谢! 不知道是什么意思以上是关于使用 pthread、互斥锁和条件变量解决哲学家就餐问题的主要内容,如果未能解决你的问题,请参考以下文章