操作系统 实验五 进程同步问题实现
实验五 进程同步问题实现一、实验目的利用实验四提供的方法和例子,解决进程同步相关问题,例如:生产者消费者问题,哲学家进餐等问题。二、实验环境硬件环境:计算机一台,局域网环境;软件环境:Linux Ubuntu操作系统,gcc编译器三、实验内容运用实验四中提供的进程同步方法实现如下问题:生产者消费者问题问题描述:一组生产者进程向一组消费者进程提供产品,两类进程共享一个由n个缓冲区组成的有界缓冲池,生
实验五 进程同步问题实现
一、实验目的
利用实验四提供的方法和例子,解决进程同步相关问题,例如:生产者消费者问题,哲学家进餐等问题。
二、实验环境
硬件环境:计算机一台,局域网环境;
软件环境:Linux Ubuntu操作系统,gcc编译器
三、实验内容
运用实验四中提供的进程同步方法实现如下问题:
- 生产者消费者问题
-
问题描述:一组生产者进程向一组消费者进程提供产品,两类进程共享一个由n个缓冲区组成的有界缓冲池,生产者进程向空缓冲池中投放产品,消费者进程从放有数据的缓冲池中取得产品并消费掉。
-
只要缓冲池未满,生产者进程就可以把产品送入缓冲池;只要缓冲池未空,消费者进程便可以从缓冲池中取走产品。
-
但禁止生产者进程向满的缓冲池再输送产品,也禁止消费者进程从空的缓冲池中提取产品。
-
为了防止对缓冲池重复操作,故规定在任何时候,只有一个主体可以访问缓冲池。
/* * @Description: 多个生产者消费者问题 * @version: * @Author: * @Date: 2021-04-30 13:53:49 * @LastEditors: Please set LastEditors * @LastEditTime: 2021-04-30 15:59:14 */ // NOTE: // *sem_init()初始化无名信号量,sem_open()是初始化有名信号量 // *第一个参数是指向信号量的指针 // *第二个参数为0,表示信号量只在这一进程的所有线程之间共享,否则,是进程间共享 // *第三个参数是初始值 // *线程互斥锁的创建,上锁与解锁 // * int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t * attr) // * 第二个参数是锁的属性 // *int pthread_mutex_lock(pthread_mutex_t *mutex) // *int pthread_mutex_unlock(pthread_mutex_t *mutex) // *int pthread_create((pthread_t *thread, pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) // * 线程标识符 // * 线程属性 // * 线程函数地址 // * 传给函数的参数 // ? 代码中如果没有pthread_join主线程会很快结束从而使整个进程结束,从而使创建的线程没有机会开始执行就结束了。加入pthread_join后,主线程会一直等待直到等待的线程结束自己才结束,使创建的线程有机会执行。 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #define PRODUCER_NUM 5 //生产者数目 #define CONSUMER_NUM 5 //消费者数目 #define POOL_SIZE 11 //缓冲池大小 int pool[POOL_SIZE]; //缓冲区 int head = 0; //缓冲池读取指针 int rear = 0; //缓冲池写入指针 sem_t empty_sem; //同步信号信号量,表示缓冲区有可用空间 sem_t full_sem; //同步信号量,表示缓冲区有可用产品 pthread_mutex_t mutex; // 缓冲区互斥访问,线程互斥锁 // 生产者 void *producer_fun(void *arg) { while (1) { sleep(1); /* 空间-- */ sem_wait(&empty_sem); // 关闭互斥信号量 pthread_mutex_lock(&mutex); //生产者往缓冲池中写入数据 pool[rear] = 1; rear = (rear + 1) % POOL_SIZE; printf("producer %d write to pool\n", (int)arg); printf("pool size is %d\n", (rear - head + POOL_SIZE) % POOL_SIZE); // 打开互斥信号量 pthread_mutex_unlock(&mutex); // 产品++ sem_post(&full_sem); } } // 消费者 void *consumer_fun(void *arg) { while (1) { int data; sleep(10); // 检查是否是产品 sem_wait(&full_sem); // 关闭互斥信号量 pthread_mutex_lock(&mutex); //消费者从缓冲池读取数据 data = pool[head]; head = (head + 1) % POOL_SIZE; printf("consumer %d read from pool\n", (int)arg); printf("pool size is %d\n", (rear - head + POOL_SIZE) % POOL_SIZE); // 打开互斥信号量 pthread_mutex_unlock(&mutex); // 空闲位置++ sem_post(&empty_sem); } } int main() { int i; pthread_t producer_id[PRODUCER_NUM]; // 生产者线程数组 pthread_t consumer_id[CONSUMER_NUM]; // 消费者线程数组 pthread_mutex_init(&mutex, NULL); //初始化互斥量 sem_init(&empty_sem, 0, POOL_SIZE - 1); //初始化信号量empty_sem为缓冲池大小 sem_init(&full_sem, 0, 0); //初始化信号量full_sem为0,开始时缓冲池中没有数据 for (i = 0; i < PRODUCER_NUM; i++) { //创建生产者线程 pthread_create(&producer_id[i], NULL, producer_fun, (void *)i); //创建消费者线程 pthread_create(&consumer_id[i], NULL, consumer_fun, (void *)i); } for (i = 0; i < PRODUCER_NUM; i++) { pthread_join(producer_id[i], NULL); pthread_join(consumer_id[i], NULL); } exit(0); }
- 哲学家进餐问题
-
有5位哲学家倾注毕生精力用于思考和吃饭,他们围坐在一张圆桌旁,在圆桌上有5个碗和5支筷子。每位哲学家的行为通常是思考,当其感到饥饿时,便试图取其左右最靠近他的筷子进餐。只有他拿到两支筷子后才能进餐,进餐完毕后,释放两支筷子并继续思考。
-
要求:采取合适的方法,防止出现死锁的问题。
/* * @Description: 哲学家进餐问题 * @version: * @Author: * @Date: 2021-04-30 14:51:12 * @LastEditors: Please set LastEditors * @LastEditTime: 2021-05-14 14:13:54 */ #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include <unistd.h> // 至多只允许4位哲学家竞争筷子,这样就一定有一个哲学家可以拿到两支筷子 #define N 5 // 五个哲学家 #define TIME_EAT 5 // 吃饭的时间 #define TIME_THINK 5 // 思考的时间 #define LIMIT 4 // 同一时间只允许4人用餐 #define left(phi_id) (phi_id + N - 1) % N // 宏函数,计算哲学家左手边的筷子,注意id可能为0,所以要+N #define right(phi_id) (phi_id + 1) % N // 宏函数,计算哲学家右手边的筷子 sem_t chopstick[N]; // 筷子互斥信号量数组 sem_t limit; // 竞争人数 void thinking(int id) { sleep(TIME_THINK); printf("philosopher[%d] is thinking...\n", id); } void eating(int id) { sleep(TIME_EAT); printf("philosopher[%d] is eating...\n", id); } void take_forks(int id) { //获取左右两边的筷子 sem_wait(&chopstick[left(id)]); sem_wait(&chopstick[right(id)]); printf("philosopher[%d] take_forks...\n", id); } void put_down_forks(int id) { printf("philosopher[%d] is put_down_forks...\n", id); sem_post(&chopstick[left(id)]); sem_post(&chopstick[right(id)]); } void *philosopher_work(void *arg) { int id = *(int *)arg; printf("philosopher init [%d] \n", id); while (1) { thinking(id); // 检查同时竞争的哲学家是否达到限制,是则阻塞等待,否则进入竞争 sem_wait(&limit); take_forks(id); // 已经拿到了筷子,退出竞争 sem_post(&limit); eating(id); // 进食完毕,释放筷子 put_down_forks(id); } } int main() { // 线程数组,相当于N个哲学家 pthread_t phiTid[N]; int i; int *id = (int *)malloc(sizeof(int) * N); // 初始化筷子信号量,初始情况是,所有筷子都空闲 for (i = 0; i < N; i++) sem_init(&chopstick[i], NULL, 1); // 初始化信号量,初始值是LIMIT,无人参与竞争 sem_init(&limit, NULL, LIMIT); for (i = 0; i < N; ++i) { id[i] = i; // 生成的thread id是0,1,2,3,4,(iny*)->(void*) pthread_create(&phiTid[i], NULL, philosopher_work, (void *)(&id[i])); } while (1) ; exit(0); }
- 和尚打水问题
-
某寺庙,有小和尚,老和尚若干。有一水缸,由小和尚提水入缸供老和尚饮用。水缸可容10桶水,水取自同一井中。水井径窄,每次中能容下一个桶取水。水桶总数为3个。每人一次取缸水仅为1桶,且不可同时进行。
/* * @Description: 和尚打水问题 * @version: * @Author: * @Date: 2021-04-30 15:27:58 * @LastEditors: Please set LastEditors * @LastEditTime: 2021-04-30 16:46:49 */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <semaphore.h> #include <stdbool.h> // mutex1是井的互斥信号量 // mutex2是缸的互斥信号量 // amount是桶的互斥信号量 // empty和full是缸的同步信号量 sem_t mutex1, mutex2, amount, empty, full; int fullcount = 0; void *LittleMonk(void *p) { while (true) { // 检查是否空,若空则打水,否则阻塞等待 sem_wait(&empty); // 检查是否有桶可用,有则去访问井,否则阻塞等待 sem_wait(&amount); // 检查有没有其他小和尚正在访问井 sem_wait(&mutex1); // 井边提水 printf("第%d个小和尚在水井提水\n", *(int *)p); // 打完水后释放井的信号量,离开井 sem_post(&mutex1); // 检查是否有其他和尚正在访问缸,若没有则倒水,否则阻塞等待 sem_wait(&mutex2); // 小和尚在水缸旁倒水 printf("水缸已有%d桶水,第%i个小和尚在水缸旁倒水\n", fullcount, *(int *)p); // 缸内水的数量++ fullcount++; // 倒水的小和尚离开缸,释放资源 sem_post(&mutex2); // 放下水桶,释放桶资源 sem_post(&amount); // 水缸里水的桶数加1 sem_post(&full); } } void *BigMonk(void *p) { while (true) { // 检查缸内是否有水,有则打水,否则阻塞等待 sem_wait(&full); // 老和尚检查是否有水桶可用,没有水桶则等待 sem_wait(&amount); // 水缸旁有人则等待,没有则开始打水 sem_wait(&mutex2); printf("\t水缸已有%d桶水,第%d个大和尚在水缸旁提水\n", fullcount, *(int *)p); // 打完水,缸内水的数量-- fullcount--; // 老和尚离开缸,释放缸互斥信号量 sem_post(&mutex2); // 老和尚放下水桶,是否同互斥信号量 sem_post(&amount); // 空闲位置++ sem_post(&empty); } } int main() { int i, j; // 保存进程的ID pthread_t little[20], big[20]; //初始化信号量 // 井互斥锁默认为1 sem_init(&mutex1, 0, 1); // 缸互斥锁默认为1 sem_init(&mutex2, 0, 1); // 开始时有3个水桶供使用 sem_init(&amount, 0, 3); // 开始时水缸里没有水,设置为0 sem_init(&full, 0, 0); // 开始时水缸里最多能装10桶水,设置为10 sem_init(&empty, 0, 10); //创建多个老和尚进程 for (i = 1; i <= 4; ++i) { int *id = &i; pthread_create(&big[i], NULL, BigMonk, (void *)id); } //创建多个小和尚进程 for (j = 1; j <= 10; ++j) { int *id = &j; pthread_create(&little[j], NULL, LittleMonk, (void *)id); } while (true) ; exit(0); }
四、实验总结
结合实验,谈谈你对进程同步的理解和体会。
- 进程同步是指并发执行的进程因直接制约关系而需相互等待,相互合作,以实现各进程按相互协调的速度向前推进的过程。同步过程中进程与进程之间有序合作,相互清楚对方的存在及其作用,进程之间直接合作完成任务。
更多推荐
所有评论(0)