当前位置: 首页 > 知识库问答 >
问题:

使用pthread、互斥锁和条件变量解决问题

司空浩邈
2023-03-14

我试图在C语言中实现用餐哲学家的问题,使用pthon、互斥锁和条件变量。

  • 它需要一个命令行参数来指定程序应该运行多长时间。我必须使用睡眠功能来完成这项任务

我的输出有一些问题:

  1. 使主函数在命令行上输入的秒数处于Hibernate状态似乎并没有使输出不同。
  2. 大多数哲学家都在渴望程序的大部分执行。
  3. 当我打印出一个哲学家在思考或吃饭时,一个“哲学家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个答案

陆正奇
2023-03-14

pthread_create将指针作为其最后一个参数传递。该指针必须在线程运行时有效,而不仅仅是在创建线程时有效。您正在使用一个指向循环变量i的指针,该变量已蒸发。

也不确定为什么在pthread_创建之前调用pthread_join,但我认为它会返回错误(您没有检查)。

 类似资料:
  • 我在C中做了一个关于线程、锁和条件变量的练习。我需要编写一个程序来获取数据,将其转换为一个链表,启动3个线程,每个线程为列表中的每个节点计算结果,主线程在evreyone完成后打印结果。 这是主要功能: 请注意,create_numbers功能正常工作,列表按预期工作。 以下是启动线程和线程功能代码: 请注意,self_id用于调试目的。 我的主要问题是分工合作。每个线程从全局链表中获取一个元素,

  • 问题内容: 我在基于linux的(arm)通信应用程序中的不可预测的时间遇到​​以下错误: Google出现了很多有关该错误的参考,但几乎没有与我的情况相关的信息。我想知道是否有人可以给我一些有关如何解决此错误的想法。有谁知道这个断言的共同原因? 提前致谢。 问题答案: 连续4天坚如磐石。我要宣布这一点的胜利。答案是“愚蠢的用户错误”(请参阅​​上面的评论)。互斥锁只能由锁定它的线程来解锁。感谢您

  • 问题内容: 天真的问题.. 我读过之前说过:“ MUTEX只能通过锁定它的线程来解锁。 ” 但是我写了一个程序,其中 THREAD1 锁定了mutexVar并进入睡眠状态。然后 THREAD2 可以直接解锁MutexVar进行一些操作并返回。 ==>我知道每个人都说我为什么这样做?但是我的问题是-这是MUTEX的正确行为吗? ==>添加示例代码 问题答案: 您所做的只是不合法的,行为是不确定的。互

  • Go语言包中的 sync 包提供了两种锁类型:sync.Mutex 和 sync.RWMutex。 Mutex 是最简单的一种锁类型,同时也比较暴力,当一个 goroutine 获得了 Mutex 后,其他 goroutine 就只能乖乖等到这个 goroutine 释放该 Mutex。 RWMutex 相对友好些,是经典的单写多读模型。在读锁占用的情况下,会阻止写,但不阻止读,也就是多个 gor

  • 本文向大家介绍浅谈互斥锁为什么还要和条件变量配合使用,包括了浅谈互斥锁为什么还要和条件变量配合使用的使用技巧和注意事项,需要的朋友参考一下 mutex体现的是一种竞争,我离开了,通知你进来。 cond体现的是一种协作,我准备好了,通知你开始吧。 互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起配合使用。

  • 问题内容: pthread问题: 似乎只有在其他线程调用pthread_cond_notify之前调用pthread_cond_wait时,条件变量才起作用。如果在等待之前以某种方式发生通知,则等待将卡住。 我的问题是: 什么时候应该使用条件变量? 调度程序可以抢占线程,并且在等待之前可能会发生通知。 等待信号量没有这个问题-它们有一个计数器。 什么时候条件变量比信号量更好? 这是一个测试: 文件