1 实验说明
利用信号量解决生产者-消费者问题。
2 解决方案
进程同步是操作系统多进程/多线程并发执行的关键之一, 进程同步指为完成共同任务的并发进程基于某个条件来协调它们的活动, 这是进程之间发生的一种直接制约关系, 生产者-消费者问题是典型的进程同步问题, 其本质是如何控制并发进程对有界共享主存区的访问。生产者进程生产产品, 然后将产品放置在一个空缓冲区中供消费者进程消费。 消费者进程从缓冲区中获得产品, 然后释放缓冲区。当生产者进程生产产品时, 如果没有空缓冲区可用, 那么生产者进程必须等待消费者进程释放出一个空缓冲区。 当消费者进程消费产品时,如果没有满的缓冲区, 那么消费者进程将被阻塞, 直到新的产品被生产出来。
下面以生产者进程不断向数组添加数据(写入 100 次), 消费者从数组读取数据并求和为例,给出基于信号量解决生产者-消费者问题的程序框架。该程序假设有一个生产者进程和两个消费者进程, 创建了 fullid、 emptyid 和 mutexid 共 3 个信号量, 供进程间同步访问临界区。 同时, 还建立 4 个共享主存区, 其中 array 用于维护生产者、消费者进程之间的共享数据, sum 保存当前求和结果, 而 set 和 get 分别记录当前生产者进程和消费者进程的读写次数。
#include <sys/mman.h> #include <sys/types.h> #include <linux/sem.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <time.h> #define MAXSEM 5 //声明三个信号灯 ID int fullid;// int emptyid; int mutxid; int main() { //fullid、 emptyid 和 mutexid 共 3 个信号量, 供进程间同步访问临界区。 struct sembuf P, V; union semun arg; //声明共享主存,实际就是一个数组 int *array;//用于维护生产者、消费者进程之间的共享数据 int *sum;//保存当前求和结果 int *set;//生产者进程 int *get;//消费者进程的读写次数 //映射共享主存 array = (int *)mmap(NULL, sizeof( int ) * MAXSEM, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); sum = (int *)mmap(NULL, sizeof( int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); get = (int *)mmap(NULL, sizeof( int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); set = (int *)mmap(NULL, sizeof( int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); *sum = 0; *get = 0; *set = 0; //生成信号灯 fullid = semget(IPC_PRIVATE, 1, IPC_CREAT | 00666); emptyid = semget(IPC_PRIVATE, 1, IPC_CREAT | 00666); mutxid = semget(IPC_PRIVATE, 1, IPC_CREAT | 00666); //为信号灯赋值 arg.val = 0;//信号量的初值 if(semctl(fullid, 0, SETVAL, arg) == -1) perror("semctl setval error"); arg.val = MAXSEM; if(semctl(emptyid, 0, SETVAL, arg) == -1) perror("semctl setval error"); arg.val = 1; if(semctl(mutxid, 0, SETVAL, arg) == -1) perror("setctl setval error"); //初始化 P,V 操作 V.sem_num = 0; V.sem_op = 1; V.sem_flg = SEM_UNDO; P.sem_num = 0; P.sem_op = -1; P.sem_flg = SEM_UNDO; printf("fullid:%d ,emptyid:%d ,mutxid:%d .\n",fullid,emptyid,mutxid); //生产者进程 if(fork() == 0 ) { //child 进程 int i = 0; while( i < 100) { semop(emptyid, &P, 1 ); semop(mutxid, &P, 1); array[*(set) % MAXSEM] = i + 1; printf("Producer %d\n", array[(*set) % MAXSEM]); (*set)++; semop(mutxid, &V, 1); semop(fullid, &V, 1); i++; } sleep(10); printf("Producer is over"); exit(0); } else { //parent 进程 //ConsumerA 进程 if(fork() == 0) { while(1) { if(*get == 100) break; semop(fullid, &P, 1); semop(mutxid, &P, 1); *sum += array[(*get) % MAXSEM]; printf("The ComsumerA Get Number %d\n", array[(*get) % MAXSEM] ); (*get)++; if( *get == 100) printf("The sum is %d \n ", *sum); semop(mutxid, &V, 1); semop(emptyid, &V, 1 ); sleep(1); } printf("ConsumerA is over\n"); exit(0); } else { //Consumer B 进程 while(1) { if(*get == 100) break; semop(fullid, &P, 1); semop(mutxid, &P, 1); *sum += array[(*get) % MAXSEM]; printf("The ComsumerB Get Number %d\n", array[(*get) % MAXSEM] ); (*get)++; if( *get == 100) printf("The sum is %d \n ", *sum); semop(mutxid, &V, 1); semop(emptyid, &V, 1 ); sleep(1); } printf("ConsumerB is over\n"); exit(0); } } //printf("fullid:%d ,emptyid:%d ,mutxid:%d .\n",fullid,emptyid,mutxid); return 0; }
运行结果:
题目:信号量实现进程同步
猜你喜欢
转载自blog.csdn.net/weixin_43442778/article/details/95448751
今日推荐
周排行