Linux下信号量实现进程同步、互斥(生产者消费者问题)
2016-10-27 15:59
821 查看
操作系统分析的一个小实验
运用Linux平台下的进程间同步和互斥机制,设计实现一个生产者进程和一个消费者进程通过共享内存交换数据,并能达到以下要求:一个仓库可以存放K件物品。生产者每生产一件产品,将产品放入仓库,仓库满了就停止生产。消费者每次从仓库中去一件物品,然后进行消费,仓库空时就停止消费。
因为有生产者、消费者以及仓库,所以需要三个信号量:full、empty和mutex分别表示仓库的库存的同步信号量、仓库为空的同步信号量和正在对仓库进行操作的互斥信号量。其初值分别为0、仓库的容量(程序中使用MAX_BUFFRT_SIZE表示)和0。流程图如图所示。
生产者:
p(empty) -> p(mutex) -> v(mutex) -> v(full)
消费者:
p(full) -> p(mutex) -> v(mutex) ->v(empty)
环境如下:Ubuntu14.04.3,gcc(4.8.2),codeblocks(13.12)
//copyright @Vista(njupt)
实验的结果如下。值得注意的是,如果输出的结果总是差不多的,那么可能要调节一下生产或者是消费的速度,用sleep就好了。有意义进程的并发性,结果几乎是随机的。
参考文献:
http://blog.csdn.net/yaozhiyi/article/details/7561759
《Linux程序设计(第四版)》
最后说一下,《Linux程序设计》这本书写的真不错,很值得学习。
博主还是菜鸟,有不对或需要改进的地方还请大牛们多多指教。
运用Linux平台下的进程间同步和互斥机制,设计实现一个生产者进程和一个消费者进程通过共享内存交换数据,并能达到以下要求:一个仓库可以存放K件物品。生产者每生产一件产品,将产品放入仓库,仓库满了就停止生产。消费者每次从仓库中去一件物品,然后进行消费,仓库空时就停止消费。
因为有生产者、消费者以及仓库,所以需要三个信号量:full、empty和mutex分别表示仓库的库存的同步信号量、仓库为空的同步信号量和正在对仓库进行操作的互斥信号量。其初值分别为0、仓库的容量(程序中使用MAX_BUFFRT_SIZE表示)和0。流程图如图所示。
生产者:
p(empty) -> p(mutex) -> v(mutex) -> v(full)
消费者:
p(full) -> p(mutex) -> v(mutex) ->v(empty)
环境如下:Ubuntu14.04.3,gcc(4.8.2),codeblocks(13.12)
//copyright @Vista(njupt)
#include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #include <sys/stat.h> #include <stdio.h> #include <unistd.h> /*KEY 为申请信号量的键值,通过键值可以用于不同进程间的通信*/ #define KEY (key_t)14010322 /*仓库大小*/ #define MAX_BUFFER_SIZE 10 /*union semun 常用于semctl的最后一个参数, 有的系统上sem.h已包含,可能会因为重复而报错, 如果报错请将其去除。*/ union semun { int val; struct semid_ds *buf; ushort *array; }; /*仓库,buffer数组用于存贮生产的商品编号(product) write用于记录生产者生产的下一个商品应存贮在仓库的位置 read用于记录消费者消费的下一个商品在仓库中的位置 很明显这是个循环队列,write、read分别为头尾指针*/ typedef struct _tagShareBuffer{ int buffer[MAX_BUFFER_SIZE]; int writer; int reader; }SHAREBUFFER; static void p(int semid ,int semNum); static void v(int semid ,int semNum); int main() { int shmid; //共享内存的id char* shmPtr; int semid; //信号量指针 int product = 1; //产品编号,从1开始 SHAREBUFFER* pSharebuffer; //共享内存的指针 int i; /*申请信号量*/ if ((semid = semget(KEY,3,IPC_CREAT|0660)) == -1) { printf("semget error! \n"); return -1; } /*三个信号量的初始赋值*/ union semun arg[3]; arg[0].val = 1; //mutex(0) arg[1].val = MAX_BUFFER_SIZE; //empty(1) arg[2].val = 0; //full(2) for(i=0;i<3;i++) semctl(semid,i,SETVAL,arg[i]); /*显示三个信号量的初值*/ for(i=0;i<3;i++) printf("The semval(%d) = %d\n",i,semctl(semid,i,GETVAL,NULL)); /*申请共享内存*/ if ((shmid = shmget(IPC_PRIVATE,sizeof(SHAREBUFFER),0600)) < 0) { printf("shmget error!\n"); return -1; } if((shmPtr = (char*)shmat(shmid,0,0)) == (void*)-1) { printf("shmat error!\n"); return -1; } memset((void*)shmPtr,0,sizeof(SHAREBUFFER)); pSharebuffer = (SHAREBUFFER*)shmPtr; /*创建进程*/ pid_t pid = fork(); if (pid < 0){ printf("creat process error.\n"); return -1; } if (pid == 0){ /*子进程,消费者*/ while(1) { p(semid ,2); //P(full) p(semid ,0); //P(mutex) /*输出三个信号量的值和消费仓库中的产品编号以及位置*/ product = pSharebuffer->buffer[pSharebuffer->reader]; for(i=0;i<3;i++) printf("son:The semval(%d) = %d\n",i,semctl(semid,i,GETVAL,NULL)); printf("son:release the product from buffer[%d] = %d;\n",pSharebuffer->reader,product); /* reader++ */ pSharebuffer->reader = (pSharebuffer->reader + 1) % MAX_BUFFER_SIZE; v(semid ,0); //V(mutex) v(semid ,1); //V(empty) sleep(1); //调节消费速度 } } else { //父进程,生产者 while(1) { p(semid ,1); //P(empty) p(semid ,0); //P(mutex) /*输出三个信号量的值和生产仓库中的产品编号以及位置*/ pSharebuffer->buffer[pSharebuffer->writer] = product; for(i=0;i<3;i++) printf("parents:The semval(%d) = %d\n",i,semctl(semid,i,GETVAL,NULL)); printf("parents:Produced the product into buffer[%d] = %d;\n",pSharebuffer->writer,product); /* 产品编号++ */ product++; /* write++ */ pSharebuffer->writer = (pSharebuffer->writer + 1) % MAX_BUFFER_SIZE; v(semid ,0); //V(mutex) v(semid, 2); //V(full) sleep(1); //调节生产速度 } } return 0; } /* p操作 */ void p(int semid ,int semNum){ struct sembuf sb; sb.sem_num = semNum; sb.sem_op = -1; sb.sem_flg = SEM_UNDO; semop(semid, &sb, 1); } /* v操作 */ void v(int semid ,int semNum){ struct sembuf sb; sb.sem_num = semNum; sb.sem_op = 1; sb.sem_flg = SEM_UNDO; semop(semid, &sb, 1); }
实验的结果如下。值得注意的是,如果输出的结果总是差不多的,那么可能要调节一下生产或者是消费的速度,用sleep就好了。有意义进程的并发性,结果几乎是随机的。
参考文献:
http://blog.csdn.net/yaozhiyi/article/details/7561759
《Linux程序设计(第四版)》
最后说一下,《Linux程序设计》这本书写的真不错,很值得学习。
博主还是菜鸟,有不对或需要改进的地方还请大牛们多多指教。
相关文章推荐
- 生产者-消费者问题实现 (linux下C同步信号量和互斥信号量的应用)
- linux中的生产者和消费者问题--信号量 互斥 同步
- 进程间同步互斥经典问题(一)生产者-消费者问题
- 用信号量做进程同步解决生产者和消费者遇到的奇怪问题
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- Linux下进程的同步互斥实例——生产者消费者
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- 消费者-生产者问题---进程的实现信号量
- 进程、线程知识点总结和同步(消费者生产者,读者写者三类问题)、互斥、异步、并发、并行、死锁、活锁的总结
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- linux 命名信号量实现进程间的互斥与同步
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- 进程同步互斥经典题之消费者与生产者问题
- Operating System-进程/线程内部通信-信号量、PV操作的实现和应用(解决哲学家进餐和生产者消费者问题)
- Linux下进程的同步互斥实例——生产者消费者
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作
- 进程同步---生产者与消费者问题以及进程同步机制--信号量及P、V操作