使用pthread_create()、pthread_join()、 pthread_ cancel ()、sem_init()、sem_wait()、sem_post()等函数的原理和使用方法; 哲学家就餐问题使用gcc编译并运行。
时间: 2024-05-06 14:15:07 浏览: 174
pthread_create():用于创建一个新线程。它接受四个参数:指向线程标识符的指针、线程属性、指向函数的指针和传递给函数的参数。
pthread_join():用于等待一个线程的结束。它接受两个参数:被等待的线程标识符和一个指向返回值的指针。
pthread_cancel():用于取消一个线程。它接受一个参数,被取消的线程标识符。
sem_init():用于初始化一个信号量。它接受三个参数:指向信号量的指针、进程间共享标识符和初始值。
sem_wait():用于等待一个信号量。它接受一个参数,指向信号量的指针。
sem_post():用于增加信号量的值。它接受一个参数,指向信号量的指针。
哲学家就餐问题是一个经典的进程同步问题。在这个问题中,五个哲学家围坐在一个圆桌前,每个哲学家面前有一盘意大利面和一只叉子。由于这些哲学家只有一个叉子,所以他们必须通过互相协作来进餐。但是,如果所有哲学家都同时拿起自己左边的叉子,那么就会出现死锁的情况。
以下是哲学家就餐问题的解决方案的一个示例程序,使用了上述函数:
```c
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define N 5 // 哲学家数目
#define LEFT (i + N - 1) % N // i 的左邻号
#define RIGHT (i + 1) % N // i 的右邻号
sem_t chopstick[N]; // N 个信号量,表示 N 个叉子的状态
sem_t mutex; // 互斥信号量,用于保证临界区的原子性操作
void *philosopher(void *arg) {
int i = *(int *)arg;
while (1) {
printf("Philosopher %d is thinking.\n", i);
sleep(3); // 思考
sem_wait(&mutex); // 进入临界区
sem_wait(&chopstick[LEFT]); // 拿起左边的叉子
sem_wait(&chopstick[RIGHT]); // 拿起右边的叉子
sem_post(&mutex); // 离开临界区
printf("Philosopher %d is eating.\n", i);
sleep(3); // 进餐
sem_post(&chopstick[LEFT]); // 放下左边的叉子
sem_post(&chopstick[RIGHT]); // 放下右边的叉子
}
}
int main() {
pthread_t tid[N];
int i;
int id[N];
sem_init(&mutex, 0, 1); // 初始化互斥信号量
for (i = 0; i < N; i++)
sem_init(&chopstick[i], 0, 1); // 初始化每个叉子的信号量
for (i = 0; i < N; i++) {
id[i] = i;
pthread_create(&tid[i], NULL, philosopher, &id[i]); // 创建线程
}
for (i = 0; i < N; i++)
pthread_join(tid[i], NULL); // 等待线程结束
return 0;
}
```
在这个程序中,chopstick 数组表示 N 个叉子的状态,初始状态为 1,表示可用。当哲学家拿起一个叉子时,对应的信号量减 1;当哲学家放下一个叉子时,对应的信号量加 1。mutex 是一个互斥信号量,用于保证临界区的原子性操作。当一个哲学家想要进餐时,他必须先获取 mutex 的锁,然后分别获取左边和右边的叉子的锁,最后释放 mutex 的锁。当一个哲学家完成进餐后,他必须先放下左边和右边的叉子,然后再释放 mutex 的锁。这样可以避免死锁的情况发生。
阅读全文