哲学家进餐问题

  • 问题描述:五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在圆桌上有五个碗和五只筷子,他们的生活方式是交替地进行思考和进餐。平时,一个哲学家进行思考,饥饿时便试图取其左右最靠近它的筷子,只有他拿到两只筷子时才能进餐。进餐毕,放下筷子继续思考。

  • 采用POSIX API内核级线程模拟此问题,且保证不会死锁。

  • 解决方案:简单的对哲学家进行编号,奇数与偶数哲学家进入临界区前对资源信号量申请时采用不同的顺序,从而保证不会出现资源-线程环路。

  • 代码:

#include <stdio.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <semaphore.h>
#include<stdlib.h>

sem_t chop[5];
int num[5] = {1,2,3,4,5};
void * philo(void *arg){
int id = *(int*)arg;
float randtime;
srand((unsigned)time(NULL));
while(1){
randtime = rand()%10;
if((id) % 2 == 0){
randtime = randtime / 9 + 1;
}
else{
randtime = randtime / 9 + 0.8;
}
sleep(randtime);
printf("philosopher %d is thinking for %.2f seconds\n",id,randtime);//生成随机数让哲学家思考随机长时间。

if(id % 2 == 0){ //采用奇偶分离策略,偶数序号哲学家与奇数序号哲学家拿筷子顺序不同避免死锁。
sem_wait(&chop[(((id)-1)%5)]);
sem_wait(&chop[((id)%5)]);

randtime = rand() % 10; //产生随机数模拟eating时间
randtime = randtime / 9 + 1;
sleep(randtime);
printf("philosopher %d is eating for %.2f seconds\n",id,randtime);

sem_post(&chop[((id)%5)]);
sem_post(&chop[(((id)-1)%5)]);
}
else{ //奇数序号哲学家与偶数序号哲学家拿筷子顺序相反。
sem_wait(&chop[((id)%5)]);
sem_wait(&chop[(((id)-1)%5)]);

randtime = rand() % 10; //产生随机数模拟eating时间。
randtime = randtime / 9 + 0.8;
sleep(randtime);
printf("philosopher %d is eating for %.2f seconds\n",id,randtime);

sem_post(&chop[(((id)-1)%5)]);
sem_post(&chop[((id)%5)]);
}
}
}

int main(){
for(int i = 0; i < 5; i++){
sem_init(&chop[i],0,1);
}
pthread_t p[5];
for(int i = 0; i < 5 ; i++){
pthread_create(&p[i],NULL,philo,&num[i]);
}
for(int i = 0; i < 5 ; i++){
pthread_join(p[i],NULL);
}

}

消费者 生产者问题

  • 问题描述:

  • 有一群生产者任务在生产产品,并将这些产品提供给消费者任务去消费。为使生产者任务与消费者进程能并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池:

    生产者任务从文件中读取一个数据,并将它存放到一个缓冲区中。

    消费者任务从一个缓冲区中取走数据,并输出此数据。

    生产者和消费者之间必须保持同步原则:不允许消费者任务到一个空缓冲区去取产品;也不允许生产者任务向一个已装满产品且尚未被取走的缓冲区中投放产品。

  • 生产者与消费者之间共享一个互斥信号量,同时设置两个资源信号量full,empty初始值分别位0和N(缓冲区大小)

  • 代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <pthread.h>
    #include <semaphore.h>
    #include <unistd.h>
    #include <time.h>
    #include <sys/file.h>

    #define MAX_SIZE 10
    #define N 10
    char *a[N] = {0}; //创建一个大小为10的缓冲区
    int pnum[3] = {1, 2, 3}; //两个数组标明producer和consumer的序号,并作为全局变量传递参数。
    int cnum[4] = {1, 2, 3, 4};
    char s[6]; //如果设成指针会出错。
    pthread_mutex_t mutex;
    pthread_mutex_t mutex1;
    sem_t empty;
    sem_t full;
    int in = 0;
    int out = 0;
    void *producer();
    void *consumer();
    int main(int argc, char *argv[])
    {
    pthread_t p[3];
    pthread_t c[4];

    pthread_mutex_init(&mutex, NULL);
    pthread_mutex_init(&mutex1, NULL);
    sem_init(&full, 0, 0);
    sem_init(&empty, 0, N); //初始化

    for (int i = 0; i < 3; i++)
    {
    pthread_create(&p[i], NULL, producer, &pnum[i]);
    }
    for (int i = 0; i < 4; i++)
    {
    pthread_create(&p[i], NULL, consumer, &cnum[i]);
    } //创建线程

    for (int i = 0; i < 3; i++)
    {
    pthread_join(p[i], NULL);
    } //加入线程

    for (int i = 0; i < 4; i++)
    {
    pthread_join(c[i], NULL);
    }

    return 0;
    }
    void *producer(void *arg)
    {

    FILE *file;
    file = fopen("re.txt", "r");
    if (file == NULL)
    {
    printf("file not exists");
    exit(0);
    }

    fgets(s, MAX_SIZE, file);

    fseek(file, 0, SEEK_SET); //每个producer先从文件中读取生产内容。
    fclose(file);

    srand((unsigned)time(NULL));
    int b = *(int *)arg;

    while (1)
    {
    sem_wait(&empty);
    pthread_mutex_lock(&mutex); //先申请有误空闲区域资源,再申请互斥操作。
    a[in] = s;
    printf("producer %d produce an %s in %d\n", b, a[in], in); //打印哪个producer在哪个缓冲区生产了产品。
    in = (in + 1) % N;

    sem_post(&full);
    pthread_mutex_unlock(&mutex);

    sleep(rand() % 10 * 0.5);
    }
    }
    void *consumer(void *arg)
    {
    int b = *(int *)arg;

    while (1)
    {
    sem_wait(&full);
    pthread_mutex_lock(&mutex); //先申请有无产品可以消费

    printf("consumer %d consume an %s from %d\n", b, a[out], out); //打印消费者从哪个缓冲区消费了产品。
    out = (out + 1) % N;

    sem_post(&empty);
    pthread_mutex_unlock(&mutex);

    sleep(rand() % 10 * 0.1);
    }
    }