操作系统课程设计:Linux系统管理实践与进程通信实现
操作系统课程设计:Linux系统管理实践与进程通信实现

操作系统课程设计——Linux系统管理实践与进程通信实现二零一三年一月八号一、设计内容1、Linux系统的熟悉与常用操作命令的掌握。
2、Linux环境下进程通信的实现。
(实现父母子女放水果吃水果的同步互斥问题,爸爸放苹果,女儿专等吃苹果,妈妈放橘子,儿子专等吃橘子,盘子即为缓冲区,大小为5。
)二、Linux环境介绍1、Linux的由来与发展Linux是一种可以在PC机上执行的类似UNIX的操作系统,是一个完全免费的操作系统。
1991年,芬兰学生Linux Torvalds开发了这个操作系统的核心部分,因为是Linux改良的minix系统,故称之为Linux。
2、Linux的优点(1)Linux具备UNIX系统的全部优点Linux是一套PC版的UNIX系统,相对于Windows是一个十分稳定的系统,安全性好。
(2)良好的网络环境Linux与UNIX一样,是以网络环境为基础的操作系统,具备完整的网络功能,提供在Internet或Intranet的邮件,FTP,www等各种服务。
(3)免费的资源Linux免费的资源和公开的源代码方便了对操作系统的深入了解,给编程爱好者提供更大的发挥空间。
3、Linux的特点1)全面的多任务,多用户和真正的32位操作系统2)支持多种硬件,多种硬件平台3)对应用程序使用的内存进行保护4)按需取盘5)共享内存页面6)使用分页技术的虚拟内存7)优秀的磁盘缓冲调度功能8)动态链接共享库9)支持伪终端设备10)支持多个虚拟控制台11)支持多种CPU12)支持数字协处理器387的软件模拟13)支持多种文件系统14)支持POSIX的任务控制15)软件移植性好16)与其它UNIX系统的兼容性17)强大的网络功能三、常用命令介绍1、目录操作和DOS相似,Linux采用树型目录管理结构,由根目录(/)开始一层层将子目录建下去,各子目录以 / 隔开。
用户login后,工作目录的位置称为 home directory,由系统管理员设定。
《Linux操作系统设计实践》实验二:进程通信

《Linux操作系统设计实践》实验二:进程通信实验目的:进一步了解和熟悉 Linux 支持的多种 IPC 机制,包括信号,管道,消息队列,信号量,共享内存。
实验环境: redhat实验内容:(1)进程间命名管道通信机制的使用:使用命名管道机制编写程序实现两个进程间的发送接收信息。
(2)进程间消息队列通信机制的使用:使用消息队列机制自行编制有一定长度的消息(1k 左右)的发送和接收程序。
(3)进程间共享存储区通信机制的使用:使用共享内存机制编制一个与上述(2)功能相同的程序。
并比较分析与其运行的快慢。
实验代码验证:(1).使用命名管道机制编写程序实现两个进程间的发送接收信息。
#include <stdio.h>#include <stdlib.h>#define FIFO_FILE "MYFIFO"int main(int argc, char *argv[]){FILE *fp;int i;if (argc<=1){printf("usage: %s <pathname>\n",argv[0]); exit(1);}if ((fp = fopen(FIFO_FILE, "w")) == NULL) {printf("open fifo failed. \n");exit(1);}for (i = 1; i < argc; i++){if (fputs(argv[i],fp) == EOF){printf("write fifo error. \n");exit(1);}if (fputs(" ",fp) == EOF){printf("write fifo error. \n"); exit(1);}}fclose(fp);return 0;}#include <stdio.h>#include <stdlib.h>#include <sys/stat.h>#include <unistd.h>#include <linux/stat.h>#define FIFO_FILE "MYFIFO"int main(){FILE *fp;char readbuf[80];if ((fp = fopen(FIFO_FILE, "r")) == NULL) {umask(0);mknod(FIFO_FILE, S_IFIFO | 0666, 0);}else{fclose(fp);}while (1){if ((fp = fopen(FIFO_FILE, "r")) == NULL) {printf("open fifo failed. \n");exit(1);}if (fgets(readbuf, 80, fp) != NULL){printf("Received string :%s \n", readbuf); fclose(fp);}else{if (ferror(fp)){printf("read fifo failed.\n");exit(1);}}}return 0;}实验结果:Server.c将client.c写入的字符输出。
操作系统实验Linux进程同步与通信操作系统二

操作系统课程实验二年级2012 级专业计算机科学与技术(应用型)指导教师黄玲学号姓名实验二、Linux进程同步与通信一、关键问题1、实验目的理解进程的高级通信;理解通过信号量实现进程的同步。
2、实验环境Ubuntu 8.0或者以上,Eclipse集成开发环境3、实验内容3.1 观察Linux进程通信下面代码实现两个进程之间通过共享内存通信。
3.2 Linux进程同步实验要求:一个生产者向一个缓冲区发消息,每当发出一个消息后,要等待三个消费者都接收这条消息后,生产者才能发送新消息。
用信号量和P、V操作,写出他们同步工作的程序。
(提示:可以把缓冲区看作是三个缓冲块组成的缓冲区,生产者等到这三个缓冲块为空时,才发送新消息到这个缓冲区。
每个消费者从一个缓冲块取走数据。
)二、设计修改思路这是一个典型的生产者消费者问题可以基于信号灯解决,由于有3个消费者,一个生产者,共用同一个缓冲区,所以我们需要设置4个信号灯来控制4个进程的互斥。
一个生产者进程不断向修改变量(写入10次),三个消费者进程从缓冲区中读取数据。
创建了empty、full1、full2、full3四个信号量,供进程间同步访问临界区,同时建立两个虚存区:a用于生产者、消费者之间的共享数据,get 记录当前生产者进程和消费者进程的读写次数。
实现的算法如下:生产者进程{p(empty);p(empty);p(empty);发送消息v(full1);v(full2);v(full3);}消费者A进程{p(full1);接受消息v(empty);}消费者B、C进程和A进程类似三、实现修改的关键代码//为信号灯赋初值arg.val = 3;if(semctl(empty , 0 , SETV AL , arg) == -1) perror("semctl setval error"); arg.val = 0;if(semctl(full1 , 0 ,SETV AL , arg) == -1) perror("semctl setval error"); arg.val = 0;if(semctl(full2 , 0 ,SETV AL , arg) == -1) perror("setctl setval error"); arg.val = 0;if(semctl(full3 , 0 ,SETV AL , arg) == -1) perror("setctl setval error");//生产者进程if(fork() == 0 ) {int i=1;while (i<11){semop(empty , &P , 1); //申请对缓冲区的互斥操作semop(empty , &P , 1); //申请对缓冲区的互斥操作semop(empty , &P , 1); //申请对缓冲区的互斥操作*a = i; //放入数据到缓冲区printf("Producer %d\n", *a);semop(full1 , &V , 1); //释放信号量semop(full2 , &V , 1);semop(full3 , &V , 1);i++;}sleep(10);printf("Producer is over");exit(0);}else {//ConsumerA 进程if(fork()==0) {while(1){if(*get==30) break;semop(full1 , &P , 1); //申请数据printf("The ComsumerA Get Number %d\n", *a );(*get)++;semop(empty , &V , 1); //释放信号量sleep(1);}printf("ConsumerA is over");exit(0);}四、程序运行结果截图五、实验总结及进一步改善建议1、通过今天的实验操作,自己初步熟悉理解进程的高级通信;理解通过信号量实现进程的同步。
操作系统实验 进程与进程通信

计算机工程学院实验报告课程名称:操作系统实验班级实验成绩:指导教师:姓名:实验项目名称:进程与进程通信学号:上机实践日期:2009-11-13实验项目编号:实验二组号:上机实践时间:2学时一、目的1、深刻理解进程和线程的概念;2、掌握线程和进程的差别以及与之相适应的通信方式;3、掌握在Linux环境下创建进程: fork()的应用;4、了解用fork()创建进程、以及整个程序的运行过程;5、掌握多进程的程序设计与进程之间通信的方法;6、掌握共享内存、信号灯集实现进程通信的方法;7、理解、掌握Linux下文件系统,以及其安装与卸载过程。
二、实验内容1、在Linux环境下,用fork()创建多个进程,分别运行不同的函数;2、一部分进程代表读者,一部分进程代表写者;用共享内存、信号灯集机制实现各个读者、写者进程之间的通信;3、掌握shmget()、shmat()、shmctl()以及semget()、semctl()、semop()等函数在进程通信中的使用方法;4、用信号灯加PV操作实现进程间的互斥与同步。
三、实验环境1、操作系统:Red Hat Linux四、实验原理1、枚举数据类型,在信号灯集初始化时使用。
该结构在sys/sem.h中没有定义,必须程序设计者自行定义。
其中:semid—已经创建的信号灯集ID,sn—操作的元素的IDunion semun{int val;struct semid_ds *buf;ushort *array;};2、对信号灯集中的某个元素进行P操作。
首先要定义一个sembuf 类型的变量(该类型已经在sys/sem.h中预定义,可以直接引用),然后对该变量的各个元素进行赋值,注意进行P操作,主要是sem_op元素赋值为 -1。
其中:semid—已经创建的信号灯集ID,sn—操作的元素的IDvoid down(int semid,int sn){/* define P operating*/struct sembuf op;op.sem_num=sn;op.sem_op=-1;op.sem_flg=0;semop(semid,&op,1);}3、对信号灯集中的某个元素进行V操作。
linux课程设计进程间通信

linux课程设计进程间通信一、教学目标本节课的教学目标是让学生了解和掌握Linux进程间通信的基本概念和常用方法。
知识目标包括:掌握进程间通信的定义、作用和分类;理解Linux系统中进程间通信的机制和原理。
技能目标包括:学会使用Linux系统中的管道、信号和共享内存等通信方法;能够编写简单的Linux进程间通信程序。
情感态度价值观目标包括:培养学生对Linux系统的兴趣和好奇心,提高学生对计算机操作系统的基本认识;培养学生团队合作精神和自主学习能力。
二、教学内容本节课的教学内容主要包括Linux进程间通信的概念、分类和机制,以及常用的进程间通信方法。
首先,介绍进程间通信的定义和作用,让学生了解进程间通信的重要性。
然后,讲解Linux系统中进程间通信的机制和原理,包括管道、信号和共享内存等方法。
接下来,通过实例演示和编程实践,让学生掌握这些通信方法的用法和特点。
最后,结合实际应用场景,讨论进程间通信在操作系统中的应用和意义。
三、教学方法为了达到本节课的教学目标,采用多种教学方法相结合的方式进行教学。
首先,采用讲授法,向学生讲解进程间通信的基本概念和原理。
其次,通过案例分析法,分析实际应用场景中的进程间通信问题,引导学生学会运用所学知识解决实际问题。
然后,利用实验法,让学生动手实践,编写进程间通信程序,加深对通信方法的理解和记忆。
最后,采用讨论法,鼓励学生积极参与课堂讨论,培养团队合作精神和批判性思维。
四、教学资源为了支持本节课的教学内容和教学方法的实施,准备以下教学资源。
首先,教材《Linux操作系统原理与应用》,作为学生学习的基础资料。
其次,参考书《Linux进程间通信》,为学生提供更深入的理论学习资料。
再次,多媒体教学课件,用于直观展示进程间通信的原理和实例。
最后,实验室设备,包括计算机和网络设备,用于学生进行进程间通信实验。
通过这些教学资源,丰富学生的学习体验,提高学习效果。
五、教学评估本节课的教学评估将采用多种方式,以全面、客观地评价学生的学习成果。
实验二 Linux进程通信

实验二 Linux进程通信一、实验目的1)了解有关Linux系统调用;2)学习有关Linux的进程创建,理解进程创建后两个并发进程的执行。
二、实验内容在Linux环境下,用C/C++语言编程,使用系统调用fork创建进程多个子进程。
(1) 调试并完成下列程序,完成实验要求:#include "stdio.h"#include "sys/types.h"#include "unistd.h"int main(){pid_t pid1;pid_t pid2;pid1 = fork();pid2 = fork();printf("pid1:%d, pid2:%d\n", pid1, pid2);}要求:A.请说出执行这个程序后,将一共运行几个进程。
B.观察运行结果,并给出分析与解释。
答:A.执行这个程序后,将一共运行4个进程。
A.运行结果如下:分析与解释:fork()函数能够建立子进程,且使得子进程得到父进程地址空的一个复制;而且,当创建成功时,如果是父进程则返回0,子进程则返回子进程的I D,但是,fork()创建的进程并不是从该程序开头开始执行,它只是和父进程一样继续执行后续代码,因此在之后的语句中,父子进程同时创建一个进程,就形成了四个进程,如图上所示。
所以,,在上面的截图中,第一次fork()函数时成功产生了父子进程pid分别为2775和0,第二次使用fork()函数时父子进程又各产生了一对父子进程父进程产生的父子进程的pid分别为2776和0,子进程产生的父子进程的pid分别为0和2777。
因为进程是并发的,他的调度我们无法干预,所以出现的结果并非都是一成不变的,执行多次后,输出的顺序有可能不一样。
(2)参考下面的相关程序实例,编写一个管道实验程序,实现两个进程之间的数据通信。
要求:父进程顺序写入若干个字符串,子进程顺序读出内容,并写入文件piple.txt,并显示出来。
进程通讯管理实验报告(3篇)

第1篇一、实验目的1. 理解进程通信的概念和原理;2. 掌握进程通信的常用机制和方法;3. 能够使用进程通信机制实现进程间的数据交换和同步;4. 增强对操作系统进程管理模块的理解。
二、实验环境1. 操作系统:Linux2. 编程语言:C3. 开发环境:GCC三、实验内容1. 进程间通信的管道机制2. 进程间通信的信号量机制3. 进程间通信的共享内存机制4. 进程间通信的消息队列机制四、实验步骤1. 管道机制(1)创建管道:使用pipe()函数创建管道,将管道文件描述符存储在两个变量中,分别用于读和写。
(2)创建进程:使用fork()函数创建子进程,实现父子进程间的通信。
(3)管道读写:在父进程中,使用read()函数读取子进程写入的数据;在子进程中,使用write()函数将数据写入管道。
(4)关闭管道:在管道读写结束后,关闭对应的管道文件描述符。
2. 信号量机制(1)创建信号量:使用sem_open()函数创建信号量,并初始化为1。
(2)获取信号量:使用sem_wait()函数获取信号量,实现进程同步。
(3)释放信号量:使用sem_post()函数释放信号量,实现进程同步。
(4)关闭信号量:使用sem_close()函数关闭信号量。
3. 共享内存机制(1)创建共享内存:使用mmap()函数创建共享内存区域,并初始化数据。
(2)映射共享内存:在父进程和子进程中,使用mmap()函数映射共享内存区域。
(3)读写共享内存:在父进程和子进程中,通过指针访问共享内存区域,实现数据交换。
(4)解除映射:在管道读写结束后,使用munmap()函数解除映射。
4. 消息队列机制(1)创建消息队列:使用msgget()函数创建消息队列,并初始化消息队列属性。
(2)发送消息:使用msgsnd()函数向消息队列发送消息。
(3)接收消息:使用msgrcv()函数从消息队列接收消息。
(4)删除消息队列:使用msgctl()函数删除消息队列。
进程间通信Linux课程设计

进程间通信Linux 课程设计一、教学目标本课程的教学目标是使学生掌握进程间通信在Linux环境下的基本原理和实现方法。
具体目标如下:1.知识目标:–了解Linux操作系统的基本概念和架构;–理解进程间通信的概念、作用和分类;–掌握Linux下进程间通信的主要方法,如管道、消息队列、共享内存和信号等;–掌握同步机制,如互斥锁、条件变量和信号量等。
2.技能目标:–能够在Linux环境下编写简单的进程间通信程序;–能够分析并解决进程间通信过程中遇到的问题;–能够运用进程间通信的原理和技巧解决实际编程中的问题。
3.情感态度价值观目标:–培养学生的团队协作意识和沟通能力;–培养学生的创新精神和自主学习能力;–培养学生对操作系统和进程间通信领域的兴趣和热情。
二、教学内容本课程的教学内容主要包括以下几个部分:1.Linux操作系统基本概念和架构;2.进程间通信的概念、作用和分类;3.Linux下进程间通信的主要方法:–消息队列;–共享内存;4.同步机制:–条件变量;5.进程间通信实例分析。
三、教学方法为了达到本课程的教学目标,将采用以下教学方法:1.讲授法:用于讲解基本概念、原理和方法;2.案例分析法:通过分析实际案例,使学生更好地理解进程间通信的原理和应用;3.实验法:让学生动手实践,培养实际编程能力;4.讨论法:鼓励学生积极参与课堂讨论,培养团队协作和沟通能力。
四、教学资源为了支持本课程的教学内容和教学方法,将准备以下教学资源:1.教材:《Linux进程间通信》;2.参考书:相关领域的经典著作和学术论文;3.多媒体资料:教学PPT、视频讲座等;4.实验设备:计算机、网络设备等。
五、教学评估为了全面、客观地评估学生的学习成果,本课程将采用以下评估方式:1.平时表现:通过课堂参与、提问、讨论等方式评估学生的积极性、主动性和团队协作能力;2.作业:布置相关的编程练习和研究报告,评估学生的理解和应用能力;3.考试:包括期中和期末考试,以闭卷形式进行,评估学生对进程间通信知识的掌握程度和实际应用能力;4.实验报告:评估学生在实验过程中的动手能力和问题解决能力。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
操作系统课程设计:Linux系统管理实践与进程通信实现操作系统课程设计——Linux系统管理实践与进程通信实现班级网络10学号 31006100姓名 YHD指导老师詹永照二零一三年一月八号一、设计内容1、Linux系统的熟悉与常用操作命令的掌握。
2、Linux环境下进程通信的实现。
(实现父母子女放水果吃水果的同步互斥问题,爸爸放苹果,女儿专等吃苹果,妈妈放橘子,儿子专等吃橘子,盘子即为缓冲区,大小为5。
)二、Linux环境介绍1、Linux的由来与发展Linux是一种可以在PC机上执行的类似UNIX的操作系统,是一个完全免费的操作系统。
1991年,芬兰学生Linux Torvalds开发了这个操作系统的核心部分,因为是Linux改良的minix系统,故称之为Linux。
2、Linux的优点(1)Linux具备UNIX系统的全部优点Linux是一套PC版的UNIX系统,相对于Windows是一个十分稳定的系统,安全性好。
(2)良好的网络环境Linux与UNIX一样,是以网络环境为基础的操作系统,具备完整的网络功能,提供在Internet或Intranet的邮件,FTP,www等各种服务。
(3)免费的资源Linux免费的资源和公开的源代码方便了对操作系统的深入了解,给编程爱好者提供更大的发挥空间。
3、Linux的特点1)全面的多任务,多用户和真正的32位操作系统2)支持多种硬件,多种硬件平台3)对应用程序使用的内存进行保护4)按需取盘5)共享内存页面6)使用分页技术的虚拟内存7)优秀的磁盘缓冲调度功能8)动态链接共享库9)支持伪终端设备10)支持多个虚拟控制台11)支持多种CPU12)支持数字协处理器387的软件模拟13)支持多种文件系统14)支持POSIX的任务控制15)软件移植性好16)与其它UNIX系统的兼容性17)强大的网络功能三、常用命令介绍1、目录操作和DOS相似,Linux采用树型目录管理结构,由根目录(/)开始一层层将子目录建下去,各子目录以 / 隔开。
用户login后,工作目录的位置称为 home directory,由系统管理员设定。
‘~’符号代表自己的home directory,例如 ~/myfile 是指自己home目录下myfile这个文件。
Linux的通配符有三种:’*’和’?’用法与DOS相同,‘-‘代表区间内的任一字符,如test[0-5]即代表test0,test1,……,test5的集合。
(1)显示目录文件 ls执行格式: ls [-atFlgR] [name] (name可为文件或目录名称)例: ls 显示出当前目录下的文件ls -a 显示出包含隐藏文件的所有文件ls -t 按照文件最后修改时间显示文件ls -F 显示出当前目录下的文件及其类型ls -l 显示目录下所有文件的许可权、拥有者、文件大小、修改时间及名称ls -lg 同上ls -R 显示出该目录及其子目录下的文件注:ls与其它命令搭配使用可以生出很多技巧(最简单的如"ls -l | more"),更多用法请输入ls --help查看,其它命令的更多用法请输入命令名 --help 查看。
(2)建新目录 mkdir执行格式: mkdir directory-name例: mkdir dir1 (新建一名为dir1的目录)(3)删除目录 rmdir执行格式: rmdir directory-name 或 rm directory-name 例:rmdir dir1 删除目录dir1,但它必须是空目录,否则无法删除rm -r dir1 删除目录dir1及其下所有文件及子目录rm -rf dir1 不管是否空目录,统统删除,而且不给出提示,使用时要小心(4)改变工作目录位置 cd执行格式: cd [name]例: cd 改变目录位置至用户login时的workingdirectorycd dir1 改变目录位置,至dir1目录cd ~user 改变目录位置,至用户的working directorycd 改变目录位置,至当前目录的上层目录cd /user 改变目录位置,至上一级目录下的user目录cd /dir-name1/dir-name2 改变目录位置,至绝对路径(Full path) cd 回到进入当前目录前的上一个目录(5)显示当前所在目录 pwd执行格式: pwd(6)查看目录大小du执行格式: du [-s] directory例:du dir1 显示目录dir1及其子目录容量(以kb为单位) du -s dir1 显示目录dir1的总容量(7)显示环境变量echo $HOME 显示家目录echo $PATH 显示可执行文件搜索路径env 显示所有环境变量(可能很多,最好用"env|more","env|grep PATH"等)(8)修改环境变量,在bash下用export,如:export PATH=$PATH:/usr/local/bin想知道export的具体用法,可以用shell的help命令:help export 2、文件操作(1)查看文件(可以是二进制的)内容 cat执行格式:cat filename或more filename 或cat filename|more例: cat file1 以连续显示方式,查看文件file1的内容more file1或 cat file1|more 以分页方式查看文件的内容(2)删除文件 rm执行格式: rm filename例: rm file?rm f*(3)复制文件 cp执行格式: cp [-r] source destination例: cp file1 file2 将file1复制成file2cp file1 dir1 将file1复制到目录dir1cp /tmp/file1 将file1复制到当前目录cp /tmp/file1 file2 将file1 复制到当前目录名为file2 cp –r dir1 dir2 (recursive copy)复制整个目录。
(4)移动或更改文件、目录名称 mv执行格式: mv source destination例: mv file1 file2 将文件file1,更名为file2mv file1 dir1 将文件file1,移到目录dir1下mv dir1 dir2(5)比较文件(可以是二进制的)或目录的内容 diff执行格式: diff [-r] name1 name2 (name1、name2同为文件或目录) 例: diff file1 file2 比较file1与file2的不同处diff -r dir1 dir2 比较dir1与dir2的不同处(6)文件中字符串的查找 grep执行格式: grep string file例: grep abc file1 查找并列出串abc所在的整行文字(7)文件或命令的路径寻找执行格式一:whereis command 显示命令的路径执行格式二:which command 显示路径及使用者所定义的别名执行格式三:whatis command 显示命令的功能摘要执行格式四:find search -path -name filename -print搜寻指定路径下某文件的路径执行格式五:locate filename根据系统预先生成的文件/目录数据库(/var/lib/slocate/slocate.db)查找匹配的文件/目录,查找速度很快,如果有刚进行的文件改变而系统未到执行定时更新数据库的时间,可以打入updatedb命令手动更新。
(8)建立文件或目录的链接 ln例: ln source target1 建立source文件(已存在)的硬链接,命名为target1ln -s source target2 建立source文件的符号链接,命名为target2以下是几个常用命令操作的截图:四、设计思想当计算机中两个或多个进程在执行时需要使用公用缓冲区,并且对该缓冲区采取了互斥措施。
这时如果并发执行这些进程就会造成CPU的极大浪费,这是操作系统设计要求不允许的。
而这种现象在操作系统和用户进程中大量存在。
因此为了解决这一问题,提出了同步的概念,即把异步环境下的一组并发进程,因直接制约而互相发送消息、互相合作、互相等待,使得各进程按一定的速度执行的过程称为进程间的同步。
在本次设计中,爸爸与妈妈、儿子与女儿的进程操作是互斥的,但是爸爸与女儿、妈妈与儿子进程之间的操作是同步的。
因此要利用进程同步的方法来实现这几者之间的操作,当然其中也包含着互斥进程,因为盘子每次只能放入或取出一个水果。
程序设计中有如下四个进程:father(),mother(),daughter(),son()。
五、数据结构1、信号量semid_mutex作为进程的公有信号量,其初始值为1,可以实现进程间的互斥,同时可以表示当前状态下盘子里可以放几个水果,实现进程间的同步。
2、信号量semid_full1为进程father()与daughter()的私有信号量,初值为0,表示当前盘子里苹果的数目。
3、信号量semid_full2为进程mother()与son()的私有信号量,初值为0,表示当前盘子里橘子的数目。
六、设计流程爸爸放苹果流程图:妈妈放橘子流程图:女儿吃苹果流程图:fathesemid_mutex<=0阻塞是放否唤醒mothersemid_mutex<=0阻塞是放否唤醒son儿子吃橘子流程图:七、源代码daughtsemid_full1<=0阻塞是吃否离开临界区son操semid_full2<=0阻塞son是吃否离开临界区#include <unistd.h>#include<stdlib.h>#include<stdio.h>#include<time.h>#include<sys/wait.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/sem.h>#include <errno.h>#include<signal.h>#include <string.h>#define SHMKEY 9090 /*共享存储区的键*/#define SEMKEY_EMPTY 9091#define SEMKEY_MUTEX 9092#define SEMKEY_FULL1 9093#define SEMKEY_FULL2 9094 /*信号量数组的键*//*注意:上面的键在系统中必须唯一*/#define BUFF_LEN 5/*缓冲区可以存放10个产品*/#define PRODUCT_LEN 1 /*每个产品是一个字符串:<=32字符*/void set_sembuf_struct(struct sembuf *sem,int semnum, int semop,int semflg) {/* 设置信号量结构 */sem->sem_num=semnum;sem->sem_op=semop;sem->sem_flg=semflg;}int begin(){char *addr, end;int shmid;int semid_empty, semid_full1,semid_full2, semid_mutex;struct sembuf sem_tmp;/*开辟共享存储区*/if ((shmid = shmget(SHMKEY, BUFF_LEN * PRODUCT_LEN+3, 0777|IPC_CREAT|IPC_EXCL)) == -1){if (errno == EEXIST){printf("The Buffer Has Existed!\n"); printf("Do You Want To Delete The Buffer(Y = yes)?\n====:");scanf("%c", &end);if(end == 'y' || end == 'Y'){/* 共享存储区、信号量并不随程序的结束而被删除,如果我们没删除的话,可以用ipcs命令查看,用ipcrm删除*//*释放缓冲区*/shmid = shmget(SHMKEY, BUFF_LEN * PRODUCT_LEN+3, 0777);if (shmctl(shmid,IPC_RMID,0) < 0)perror("shmctl: falsed");/*同时释放信号量*/semid_mutex = semget(SEMKEY_MUTEX,1, 0777);/*获取全局信号量id*/semid_empty = semget(SEMKEY_EMPTY,1,0777);semid_full1 = semget(SEMKEY_FULL1,1, 0777);semid_full2 = semget(SEMKEY_FULL2,1, 0777);semctl(semid_mutex,0,IPC_RMID);semctl(semid_empty,0,IPC_RMID);semctl(semid_full1,0,IPC_RMID);semctl(semid_full2,0,IPC_RMID);}}elseprintf("Fail To Create Buffer!\n");return -1;}addr = (char*)shmat(shmid, 0, 0);/*连接缓冲区*/memset(addr, 0, BUFF_LEN * PRODUCT_LEN+3); //初始化存储区为0shmdt(addr); /*离开缓冲区*//*创建3个信号量:1个用于对缓冲区互斥,2个用于生产者、消费者同步*/0777|IPC_CREAT|IPC_EXCL))==-1){if (errno == EEXIST)printf("The SEMKEY_MUTEX Has Existed!\n");elseprintf("Fail To Create SEMKEY_MUTEX!\n");return -1;}if((semid_empty= semget(SEMKEY_EMPTY,1, 0777|IPC_CREAT|IPC_EXCL))==-1){if (errno == EEXIST)printf("The SEMKEY_EMPTY Has Existed!\n");elseprintf("Fail To Create SEMKEY_EMPTY!\n");return -1;}0777|IPC_CREAT|IPC_EXCL))==-1){if (errno == EEXIST)printf("The SEM_FULL1 Has Existed!\n");elseprintf("Fail To Create SEM_FULL1!\n");return -1;}if((semid_full2= semget(SEMKEY_FULL2,1, 0777|IPC_CREAT|IPC_EXCL))==-1){if (errno == EEXIST)printf("The SEM_FULL2 Has Existed!\n");elseprintf("Fail To Create SEM_FULL2!\n");return -1;}/*给信号量赋初值*/set_sembuf_struct(&sem_tmp, 0, BUFF_LEN, 0);/*BUFF_LEN*/semop(semid_empty, &sem_tmp,1);set_sembuf_struct(&sem_tmp, 0, 0, 0);/*0*/semop(semid_full1, &sem_tmp,1);set_sembuf_struct(&sem_tmp, 0, 0, 0);/*0*/semop(semid_full2, &sem_tmp,1);set_sembuf_struct(&sem_tmp, 0, 1, 0);/*1*/semop(semid_mutex, &sem_tmp,1);return 0;}/*下面的P,V是对系统调用的简单封装*/int P(int semid){struct sembuf p_buf;p_buf.sem_num = 0;p_buf.sem_op = -1;p_buf.sem_flg = 0;if(semop(semid, &p_buf, 1)==-1)/*semop 参见课件ppt*/{perror ("p (semid) falsed");exit (1);}elsereturn 0;}int V(int semid){struct sembuf v_buf;/*struct 参见课件ppt*/v_buf.sem_num = 0;v_buf.sem_op = 1;v_buf.sem_flg = 0;if(semop(semid, &v_buf, 1)==-1) {perror (" v (semid) failed");exit (1);}elsereturn 0;}int father(){int semid_empty, semid_full1,semid_full2, semid_mutex;/*信号量集合id*/int rc1,rc2,rc3;semid_mutex = semget(SEMKEY_MUTEX,1, 0777);/*获取全局信号量id*/semid_empty = semget(SEMKEY_EMPTY,1, 0777);semid_full1 = semget(SEMKEY_FULL1,1, 0777);semid_full2 = semget(SEMKEY_FULL2,1,0777);rc1=semctl(semid_empty,0,GETVAL);rc2=semctl(semid_mutex,0,GETVAL);if(rc1==0){return 1; //不能放則等待}if(rc2==0 ){return 1;}P(semid_empty);/*对私有信号量作P操作*/P(semid_mutex);printf("there is %d places to put apples\n",rc1);printf("PUT AN APLLE\n");V(semid_mutex);V(semid_full1);rc3=semctl(semid_full1,0,GETVAL);printf("daughter can get %d apples\n",rc3);return 0;}int mother(){ int semid_empty, semid_full1,semid_full2, semid_mutex;/*信号量集合id*/int rc1,rc2,rc3;semid_mutex = semget(SEMKEY_MUTEX,1, 0777);/*获取全局信号量id*/semid_empty = semget(SEMKEY_EMPTY,1, 0777);semid_full1 = semget(SEMKEY_FULL1,1, 0777);semid_full2 = semget(SEMKEY_FULL2,1, 0777);rc1=semctl(semid_empty,0,GETVAL);rc2=semctl(semid_mutex,0,GETVAL);if(rc1==0){return 1; //不能放則等待}else if(rc2==0){return 1;}P(semid_empty);/*对私有信号量作P操作*/ P(semid_mutex);printf("there is %d places to put oranges\n",rc1);printf("PUT AN ORANGE!!!\n");V(semid_mutex);V(semid_full2);rc3=semctl(semid_full2,0,GETVAL);printf("son can get %d oranges\n",rc3); return 0;}int son(){int semid_empty, semid_full1,semid_full2, semid_mutex;/*信号量集合id*/int rc1,rc2;semid_mutex = semget(SEMKEY_MUTEX,1, 0777);/*获取全局信号量id*/semid_empty = semget(SEMKEY_EMPTY,1, 0777);semid_full1 = semget(SEMKEY_FULL1,1, 0777);semid_full2 = semget(SEMKEY_FULL2,1, 0777);rc2=semctl(semid_full1,0,GETVAL);rc1=semctl(semid_full2,0,GETVAL);if(rc1==0){return 1; //不能放則等待}P(semid_full2);/*对私有信号量作P操作*/P(semid_mutex);printf("SUM:%d apples and %d oranges\n",rc2,rc1);printf("there is %d oranges to get \n",rc1);printf("GET AN ORANGE !!!\n");V(semid_empty);V(semid_mutex);return 0;}int daughter(){int semid_empty, semid_full1,semid_full2, semid_mutex;/*信号量集合id*/int rc1,rc2,rc3;semid_mutex = semget(SEMKEY_MUTEX,1, 0777);/*获取全局信号量id*/semid_empty = semget(SEMKEY_EMPTY,1, 0777);semid_full1 = semget(SEMKEY_FULL1,1, 0777);semid_full2 = semget(SEMKEY_FULL2,1, 0777);rc2=semctl(semid_full1,0,GETVAL);rc1=semctl(semid_full2,0,GETVAL);if(rc2==0){return 1; //不能放則等待}P(semid_full1);P(semid_mutex);printf("SUM:%d apples and %d oranges\n",rc2,rc1);printf("there is %d apples to get \n",rc2);printf("GET AN APPLE\n");V(semid_empty);V(semid_mutex);return 0;}int main(){int pid;int i = 0, x;begin();pid = fork();if(fork()==0){father();}if(fork()==0){mother();}if(fork()==0){daughter();}if(fork()==0){son();}return 0;}八、调试与运行首先,利用g++ ks.cpp编译一次,若有错误,则根据错误提示对程序进行修改。