操作系统实验三进程地管道通信
- 格式:doc
- 大小:91.32 KB
- 文档页数:11
实验三进程的管道通信一、实验目的:(1)加深对进程概念的理解,明确进程和程序的区别;(2)学习进程创建的过程,进一步认识并发执行的实质;(3)分析进程争用资源的现象,学习解决进程互斥的方法;(4)学习解决进程同步的方法;(5)掌握Linux系统进程间通过管道通信的具体实现方法。
二、实验内容及要求:(1)使用系统调用pipe()建立一条管道线,两个子进程分别向管道写一句话(写的内容自己定,但要有该进程的一些信息);(2)父进程从管道中读出来自两个子进程的消息,显示在屏幕上;(3)要求:父进程首先接收子进程p1发来的消息,然后再接收子进程p2发来的消息;(4)两个子进程要并发执行;(5)实现管道的互斥使用。
当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。
使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定;(6)实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
三、实现:相关的系统调用fork() 用于创一个子进程。
格式:int fork();返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。
wait() 常用来控制父进程与子进程的同步。
在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。
当子进程结束时,父进程从wait()返回继续执行原来的程序。
返回值:大于0时,为子进程的ID值;等于-1时,调用失败。
exit() 是进程结束时最常调用的。
格式:void exit( int status); 其中,status为进程结束状态。
pipe() 用于创建一个管道格式:pipe(int fd);其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1]是管道的写端口,用于向管道写入数据。
进程实验3 Linux 进程间通信一、软中断信号的处理,实现同一用户的各进程之间的通信。
●相关的系统调用⏹kill(pid ,sig):发送信号⏹signal(sig, func):指定进程对信号sig的处理行为是调用函数func。
●程序清单#include <unistd.h>#include <stdio.h>#include <signal.h>void waiting();void stop();int wait_mark;main(){int p1,p2;while((p1=fork())==-1);if(p1>0){while((p2=fork())==-1);if(p2>0){ printf("parent\n");/*父进程在此完成某个操作、或接收到用户从键盘输入的特殊按键命令后发出下面的信号。
这里省略。
*/kill(p1,16);kill(p2,17);wait(0);wait(0);printf("parent process id killed! \n");exit(0);}else/* p2==0*/{printf("p2\n");wait_mark=1;signal(17,stop);waiting();printf("child process 2 is killed by parent! \n");exit(0);}}else/*p1==0*/{printf("p1\n");wait_mark=1;signal(16,stop);waiting();printf("child process 1 is kelled by parent! \n");exit(0);}}void waiting(){while(wait_mark!=0);}void stop(){wait_mark=0;}●输入并运行此程序,分析程序的运行结果。
实验三线程控制和进程间通信一、实验目的通过Linux管道通信机制、消息队列通信机制的使用,加深对不同类型的进程通信方式的理解。
二、实验内容:1.熟悉Linux的管道通信机制2.熟悉Linux的消息队列通信机制三、思考1.有名管道和无名管道之间有什么不同?2.管道的读写与文件的读写有什么异同?3.Linux消息队列通信机制中与教材中的消息缓冲队列通信机制存在哪些异同?四、实验指导<一>Linux管道通信机制管道是所有UNIX都提供的一种进程间通信机制,它是进程之间的一个单向数据流,一个进程可向管道写入数据,另一个进程则可以从管道中读取数据,从而达到进程通信的目的。
1.无名管道无名管道通过pipe()系统调用创建,它具有如下特点:(1)它只能用于具有亲缘关系的进程(如父子进程或者兄弟进程)之间的通信。
(2)管道是半双工的,具有固定的读端和写端。
虽然pipe()系统调用返回了两个文件描述符,但每个进程在使用一个文件描述符之前仍需先将另一个文件描述符关闭。
如果需要双向的数据流,则必须通过两次pipe()建立起两个管道。
(3)管道可以看成是一种特殊的文件,对管道的读写与文件的读写一样使用普通的read、write等函数,但它不是普通的文件,也不属于任何文件系统,而只存在于内存中。
2.pipe系统调用(1)函数原型#include <unistd.h>int pipe(int filedes[2]);(2)参数filedes参数是一个输出参数,它返回两个文件描述符,其中filedes[0]指向管道的读端,filedes[1]指向管道的写端。
(3)功能pipe在内存缓冲区中创建一个管道,并将读写该管道的一对文件描述符保存在filedes所指的数组中,其中filedes[0]用于读管道,filedes[1]用于写管道。
(4)返回值成功返回0;失败返回-1,并在error中存入错误码。
(5)错误代码EMFILE:进程使用的文件描述符过多ENFILE :系统文件表已满EFAULT :非法参数filedes3.无名管道的阻塞型读写管道缓冲区有4096B的长度限制,因此,采用阻塞型读写方式时,当管道已经写满时,写进程必须等待,直到读进程取走信息为止。
一、实验目的1. 理解进程通信的概念和作用。
2. 掌握进程通信的常用方法,包括管道、消息队列、信号量等。
3. 通过编程实践,加深对进程通信机制的理解和应用。
二、实验环境操作系统:Linux开发环境:gcc三、实验内容1. 管道通信2. 消息队列通信3. 信号量通信四、实验步骤及分析1. 管道通信(1)实验步骤1)创建一个父进程和一个子进程;2)在父进程中创建一个管道,并将管道的读端和写端分别赋给父进程和子进程;3)在父进程中,通过管道的写端发送数据给子进程;4)在子进程中,通过管道的读端接收父进程发送的数据;5)关闭管道的读端和写端;6)结束进程。
(2)实验分析通过管道通信,实现了父进程和子进程之间的数据传递。
管道是半双工通信,数据只能单向流动。
在本实验中,父进程向子进程发送数据,子进程接收数据。
2. 消息队列通信(1)实验步骤1)创建一个消息队列;2)在父进程中,向消息队列中发送消息;3)在子进程中,从消息队列中接收消息;4)删除消息队列;5)结束进程。
(2)实验分析消息队列是一种进程间通信机制,允许不同进程之间传递消息。
消息队列的创建、发送、接收和删除等操作都是通过系统调用实现的。
在本实验中,父进程向消息队列发送消息,子进程从消息队列接收消息,实现了进程间的消息传递。
3. 信号量通信(1)实验步骤1)创建一个信号量;2)在父进程中,对信号量执行P操作,请求资源;3)在子进程中,对信号量执行V操作,释放资源;4)结束进程。
(2)实验分析信号量是一种用于实现进程同步的机制。
在进程通信中,信号量可以用来协调多个进程对共享资源的访问。
在本实验中,父进程和子进程通过信号量实现了对共享资源的同步访问。
五、实验结果1. 管道通信实验结果:父进程成功向子进程发送数据,子进程成功接收数据。
2. 消息队列通信实验结果:父进程成功向消息队列发送消息,子进程成功从消息队列接收消息。
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()函数删除消息队列。
实验三进程间的通信1、实验目的学习如何利用管道机制、消息缓冲队列进行进程间的通信,并加深对上述通信机制的理解。
2、实验内容(1)了解系统调用pipe()、msgget()、msgsnd()、msgrcv()的功能和实现过程。
(2)编写一段程序,使其用管道来实现父子进程之间的进程通信。
子进程向父进程发送自己的进程标识符,以及字符串“is sending a message to parent!”。
父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。
(3)编写一段程序,使用消息缓冲队列来实现client进程和server进程之间的通信。
server进程先建立一个关键字为SVKEY (如75)的消息队列,然后等待接收类型为REQ(如1)的消息;在收到请求消息后,它便显示字符串“serving for client”和接收到的client进程的进程标识数,表示正在为client进程服务;然后再向client进程发送一应答消息,该消息类型是client 进程的进程标识数,而正文则是server进程自己的标识数。
client进程则向消息队列发送类型为REQ的消息(消息的正文为自己的进程标识数)以取得server进程的服务,并等待server 进程发来的应答;然后显示字符串“receive reply form”和接收到的server进程的标识符。
1、client.c2、server.c3、思考题上述通信机制各有什么特点?它们分别适合于何种场合?答:管道通信的特点:(1)管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;(2)只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);(3)单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
(4)数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。
操作系统实验报告实验三、进程通信(一)——管道及共享存一、实验目的1)加深对管道通信的了解2)掌握利用管道进行通信的程序设计3)了解共享存通信的程序设计方法4)了解和熟悉Linux支持的共享存储区机制二、实验容任务一、(1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析。
(2)编写程序:父进程利用管道将一字符串交给子进程处理。
子进程读字符串,将里面的字符反向后再交给父进程,父进程最后读取并打印反向的字符串。
任务二、(1)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享存的情况,对两次的结果进行比较,并分析原因。
最后用ipcrm命令删除自己建立的共享存储区。
(有关ipcs和ipcrm介绍见后面一页)(2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。
运行结束后可以用ctrl+c结束程序1的运行。
(3)编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。
要求在父进程中生成一个30字节长的私有共享存段。
接下来,设置一个指向共享存段的字符指针,将一串大写字母写入到该指针指向的存贮区。
调用fork()生成子进程,让子进程显示共享存段中的容。
接着,将大写字母改成小写,子进程修改共享存中的容。
之后,子进程将脱接共享存段并退出。
父进程在睡眠5秒后,在此显示共享存段中的容(此时已经是小写字母)。
三、代码及运行结果分析(1)阅读以上父子进程利用管道进行通信的例子(例1),写出程序的运行结果并分析实验代码:#include<stdio.h>main(){ int x,fd[2];char buf[30],s[30];pipe(fd);while ((x=fork())==-1);if (x==0){close(fd[0]);printf("Child Process!\n");strcpy(buf,"This is an example\n");write(fd[1],buf,30);exit(0);}else{close(fd[1]);printf("Parent Process!\n");read(fd[0],s,30);printf("%s\n",s);}}运行结果:分析:调用pipe(fd);创建一个管道后,接着调用fork()函数产生两个进程,首先开始执行子进程,关闭管道出口,通过管道入口向管道中写入容。
进程的管道通信实验报告一、实验目的本实验旨在通过实际操作,深入理解进程间通信(IPC)的原理,掌握管道通信的实现方法,提高对操作系统进程管理的理解。
二、实验环境实验环境为Linux操作系统,使用Shell脚本进行进程的管道通信实验。
三、实验内容1. 创建两个Shell脚本文件,分别命名为sender.sh和receiver.sh。
2. 在sender.sh中,编写一个简单的程序,用于向管道中写入数据。
程序包括一个无限循环,每次循环中随机生成一个数字并写入管道。
3. 在receiver.sh中,编写一个简单的程序,用于从管道中读取数据。
程序同样包括一个无限循环,每次循环中从管道中读取一个数字并输出。
4. 使用Shell命令将sender.sh和receiver.sh链接起来,实现进程间的管道通信。
四、实验过程1. 打开两个终端窗口,分别用于运行sender.sh和receiver.sh。
2. 在第一个终端窗口中,输入命令“bash sender.sh”运行sender.sh脚本。
该脚本将创建一个无限循环,每次循环中随机生成一个数字并写入管道。
3. 在第二个终端窗口中,输入命令“bash receiver.sh”运行receiver.sh脚本。
该脚本将创建一个无限循环,每次循环中从管道中读取一个数字并输出。
4. 观察两个终端窗口的输出,可以看到sender.sh进程向管道中写入的数字被receiver.sh进程读取并输出。
五、实验总结通过本次实验,我们成功实现了进程间的管道通信。
在实验过程中,我们深入了解了进程间通信的原理和实现方法,掌握了管道通信的基本操作。
通过实际操作,我们更好地理解了操作系统中进程管理、进程间通信的相关知识。
同时,我们也发现了一些不足之处,例如在程序中没有添加异常处理机制等。
在今后的学习中,我们将继续深入探索进程间通信的相关知识,提高自己的编程技能和系统设计能力。
进程的管道通信实验是一个非常有用的实验,它允许两个进程之间进行数据交换。
这个实验主要涉及到了管道、管道缓冲区以及进程之间的通信机制。
以下是对这个实验的总结:
1. 管道的概念和作用:
管道是一种用于进程间通信的机制,它允许两个进程之间进行数据交换。
在管道通信实验中,我们创建了一个管道,并使用它来在两个进程之间传递数据。
管道的作用是连接两个进程,使得它们可以相互发送和接收数据。
2. 管道缓冲区:
管道缓冲区是管道中的一个重要概念。
当一个进程向管道写入数据时,数据会被写入缓冲区中,等待另一个进程读取。
当缓冲区中的数据被读取后,缓冲区中的数据会被移除,为新的数据腾出空间。
3. 进程间的通信:
在管道通信实验中,我们创建了两个进程,并使用管道来在它们之间进行通信。
一个进程向管道写入数据,另一个进程从管道读取数据。
通过这种方式,两个进程可以相互发送和接收数据。
4. 实验中的问题和解决方案:
在实验中,我们遇到了一些问题,如管道中的数据读写错误、进程间的通信问题等。
为了解决这些问题,我们采取了一些措施,如检查数据的读写是否正确、确保进程间的通信畅通等。
5. 实验的意义和收获:
通过这个实验,我们深入了解了进程间通信的概念和机制,并掌握了管道通信的基本原理和方法。
此外,我们还学会了如何解决实验中遇到的问题,提高了我们的编程能力和解决问题的能力。
总之,进程的管道通信实验是一个非常有意义的实验,它让我们深入了解了进程间通信的原理和方法。
通过这个实验,我们不仅掌握了相关的知识和技能,还提高了我们的编程能力和解决问题的能力。
暨南大学本科实验报告专用纸课程名称《操作系统原理实验》成绩评定实验项目名称进程通信指导教师戴红实验项目编号0806002903 实验项目类型综合型实验地点学生姓名蔡高成学号2007052431学院国际商学院系企业管理专业信息管理与信息系统实验时间年月日下午温度℃湿度一、实验目的学习如何利用管道机制或消息缓冲队列进行进程间的通信,并加深对上述通信机制的理解。
提高学生分析问题和解决问题的能力,并学习撰写规范的科学研究报告。
二、实验环境及设备(一)实验室名称:计算机实验室(二)主要仪器设备:PC机、Linux操作系统环境三、实验内容编写一段程序,使用管道来实现父子进程之间的进程通信。
子进程项父进程发送自己的进程表示符,以及某字符串。
父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。
四、实验调试分析1、实验函数说明(1)pipe头文件:#include<unistd.h>定义函数:int pipe(int pipedes[2]);函数说明:pipe()会建立管道,并将文件描述词由参数pipedes 数组返回。
pipedes[0]为管道里的读取端,所以pipe用read调用的pipedes[1]则为管道的写入端。
写进程A pipedes[1]返回值: 若成功则返回零,否则返回-1,错误原因存于errno 中。
错误代码:EMFILE 进程已用完文件描述词最大量ENFILE 系统已无文件描述词可用。
EFAULT 参数pipedes 数组地址不合法。
(2)sprintf函数功能:把格式化的数据写入某个字符串头文件:#include <stdio.h>函数原型:int sprintf( char *buffer, const char *format [, argument] … );返回值:字符串长度(strlen)(3)flock头文件: #include<sys/file.h>定义函数: int flock(int fd,int operation);函数说明: flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。
对观察到的内容做详细记录分析, 并写出实验报告。
对观察到的内容做详细记录分析,并写出实验报告。
四、实验过程与分析1.使用无名管道pipe(), 进行父子进程之间的通信。
编写的程序如下:运行结果如下:结果分析:父进程首先被调用时, 运行结果为:之后父进程阻塞等待子进程终止, 当系统调度子进程运行时, 输出如下的信息:之后父进程被唤醒, 调度运行, 输出如下结果后程序退出。
对于以上的结果: 首先父进程使用pipe(chan1)系统调用打开一个无名管道, 之后创建一个子进程。
子进程复制父进程的打开文件表。
为了正确通信, 父进程关闭读通道close(chan1[0]), 子进程关闭写通道close(chan1[1])。
父进程向管道写, 子进程从管道读。
完成一次通信之后, 父进程分别关闭自己的写/读通信, 管道文件消失。
2.以命名行为参数的管道文件的示例。
(假设有一个可执行程序chcase, 从标准输入设备读字符, 将小写字母转化成大写字母并输出。
主程序使用popen创建管道, 实现蒋某文本文件中的字幕转化成大写字母, 其中的文本文件名作为参数传进来。
)编写的程序如下:运行结果是:结果分析: 通过程序运行结果可知, 先打开文本文件, 如果文本打开失败, 则执行exit(1), 退出程序, 如果文本通过函数开成功, 则popen创建一个可写管道, 将命令行chcase的输入与管道的输入连接起来, 然后向管道输入数据, 此时命令行就可以通过管道接受文本文件的数据了,在从文件中读出数据时, 独处的内容放在line[]数组中,fpin表示从刚打开的文件里读出。
之后要编写字母大小写转化函数, 来实现小写字母转化成大写字母。
3.创建有名管道。
编写的程序如下:运行结果是:前台运行结果:后台运行结果:结果分析: 此程序是把管道和命令联系起来, read( )的系统调用格式是read(fd,buf,n), 参数定义是int read(fd,buf,n); int fd; char *buf; unsigned n;它的功能是从fd所指示的文件中读出n个字节的数据, 并将它们送至由指针buf所指示的缓冲区中。
操作系统实验三进程的管道通信操作系统中的进程通信是指进程之间通过一定机制进行信息传递和交换的过程。
而管道是常用的进程间通信(IPC)机制之一,它提供了一种半双工的通信方式,用于在具有亲缘关系的进程之间进行通信。
本实验以Linux系统为例,介绍进程的管道通信。
一、进程间通信(IPC)概述进程之间的通信是操作系统的重要功能之一,它使得不同进程能够共享信息、协调工作。
Linux系统提供了多种进程间通信的方式,如管道、消息队列、信号、共享内存等。
其中,管道是最简单、最常用的一种进程间通信方式。
二、管道的概念与原理1.管道的概念管道是一种特殊的文件,用于实现具有亲缘关系的进程之间的通信。
整个管道可以看作是一个字节流,其中写入的数据可以被读取。
管道通常是半双工的,即数据只能从一个进程流向另一个进程,而不能反向流动。
2.管道的原理管道的内部实现是通过操作系统的缓冲区来完成的。
当一个进程往管道写入数据时,数据被放置在写管道的缓冲区中。
另一个进程从管道中读取数据时,数据被从读管道的缓冲区中取出。
如果写管道的缓冲区为空,写操作将会阻塞,直到有数据被写入为止。
同样,如果读管道的缓冲区为空,读操作将会阻塞,直到有数据可读为止。
三、管道的使用步骤1.打开管道在Linux系统中,使用`pipe`系统调用来创建管道。
它接受一个包含两个整数的参数数组,返回0表示成功,负数表示失败。
成功创建管道后,会得到两个文件描述符,分别代表读管道和写管道。
2.进程间通信在有亲缘关系的进程中,可以使用`fork`系统调用来创建一个子进程。
父进程和子进程都可以使用管道进行读写操作。
父进程可以关闭写管道描述符,子进程关闭读管道描述符,即父进程只负责写入数据,子进程负责读取数据。
3.写入数据父进程在写管道描述符上调用`write`函数来向管道写入数据。
该函数的返回值为成功写入的字节数,返回-1表示写入失败。
4.读取数据子进程在读管道描述符上调用`read`函数来从管道读取数据。
操作系统实验三进程的管道通信Company number:【0089WT-8898YT-W8CCB-BUUT-202108】实验三进程的管道通信一、实验目的:(1)加深对进程概念的理解,明确进程和程序的区别;(2)学习进程创建的过程,进一步认识并发执行的实质;(3)分析进程争用资源的现象,学习解决进程互斥的方法;(4)学习解决进程同步的方法;(5)掌握Linux系统进程间通过管道通信的具体实现方法。
二、实验内容及要求:(1)使用系统调用pipe()建立一条管道线,两个子进程分别向管道写一句话(写的内容自己定,但要有该进程的一些信息);(2)父进程从管道中读出来自两个子进程的消息,显示在屏幕上;(3)要求:父进程首先接收子进程p1发来的消息,然后再接收子进程p2发来的消息;(4)两个子进程要并发执行;(5)实现管道的互斥使用。
当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。
使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定;(6)实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
三、实现:相关的系统调用fork() 用于创一个子进程。
格式:int fork();返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。
wait() 常用来控制父进程与子进程的同步。
在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。
当子进程结束时,父进程从wait()返回继续执行原来的程序。
返回值:大于0时,为子进程的ID值;等于-1时,调用失败。
exit() 是进程结束时最常调用的。
格式:void exit( int status); 其中,status为进程结束状态。
pipe() 用于创建一个管道格式:pipe(int fd);其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1]是管道的写端口,用于向管道写入数据。
本科实验报告专用纸课程名称操作系统原理成绩评定实验项目名称进程间的通信指导教师实验项目编号实验项目类型实验地点学生姓名学号学院系专业实验时间年月日上午~月日上午温度℃湿度一、实验目的和要求1.实验目的:1.学习如何利用管道机制或消息缓冲队列进行进程间的通信,并加深对上述通信机制的理解。
提高学生分析问题和解决问题的能力,并学习撰写规范的科学研究报告(论文)。
2.实验要求:了解系统pipe(),msgsnd(),msgrcv()的功能和实现过程。
二、实验原理和主要内容1.实验内容:(1)编写一段程序,使用管道来实现父子进程之间的进程通信。
子进程向父进程发送自己的进程表示符,以及某字符串。
父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。
(2)编写一段程序,使其用消息缓冲队列来实现client和server 进程之间的通信。
2.实验原理:(使用的系统调用命令说明或算法及程序详细设计)3.实验函数说明(1)包含头文件#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>(2)msgsnd()函数int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);//将消息送入消息队列参数:msqid:消息队列的识别码。
msgp:指向消息缓冲区的指针,此位置用来暂时存储发送和接收的消息,是一个用户可定义的通用结构,形态如下struct msgbuf {long mtype; /* 消息类型,必须> 0 */char mtext[1]; /* 消息文本*/};msgsz:消息的大小。
msgtyp:从消息队列内读取的消息形态。
如果值为零,则表示消息队列中的所有消息都会被读取。
msgflg:用来指明核心程序在队列没有数据的情况下所应采取的行动。
实验三进程的管道通信
一、实验目的:
(1)加深对进程概念的理解,明确进程和程序的区别;
(2)学习进程创建的过程,进一步认识并发执行的实质;
(3)分析进程争用资源的现象,学习解决进程互斥的方法;
(4)学习解决进程同步的方法;
(5)掌握Linux系统进程间通过管道通信的具体实现方法。
二、实验内容及要求:
(1)使用系统调用pipe()建立一条管道线,两个子进程分别向管道写一句话(写的内容自己定,但要有该进程的一些信息);
(2)父进程从管道中读出来自两个子进程的消息,显示在屏幕上;(3)要求:父进程首先接收子进程p1发来的消息,然后再接收子进程p2发来的消息;
(4)两个子进程要并发执行;
(5)实现管道的互斥使用。
当一个子进程正在对管道进行写操作时,另一个欲写入管道的子进程必须等待。
使用系统调用lockf(fd[1],1,0)实现对管道的加锁操作,用lockf(fd[1],0,0)解除对管道的锁定;
(6)实现父子进程的同步,当父进程试图从一空管道中读取数据时,便进入等待状态,直到子进程将数据写入管道返回后,才将其唤醒。
三、实现:
相关的系统调用
fork() 用于创一个子进程。
格式:int fork();
返回值:在子进程中返回0;在父进程中返回所创建的子进程的ID值;当返回-1时,创建失败。
wait() 常用来控制父进程与子进程的同步。
在父进程中调用wait(),则父进程被阻塞,进入等待队列,等待子进程结束。
当子进程结束时,父进程从wait()返回继续执行原来的程序。
返回值:大于0时,为子进程的ID值;等于-1时,调用失败。
exit() 是进程结束时最常调用的。
格式:void exit( int status); 其中,status为进程结束状态。
pipe() 用于创建一个管道
格式:pipe(int fd);
其中fd是一个由两个数组元素fd[0]和fd[1]组成的整型
数组,fd[0]是管道的读端口,用于从管道读出数据,fd[1]是管道的写端口,用于向管道写入数据。
返回值:0 调用成功;-1 调用失败。
sleep() 使调用进程睡眠若干时间,之后唤醒。
格式:sleep(int t); 其中t为睡眠时间。
lockf() 用于对互斥资源加锁和解锁。
在本实验中该调用的格式为: lockf(fd[1],1,0);/* 表示对管道的写入端口加锁。
lockf(fd[1],0,0);/* 表示对管道的写入端口解锁。
write(fd[1],String,Length) 将字符串String的内容写入管道的写入口。
read(fd[0],String,Length) 从管道的读入口读出信息放入字符串String中。
程序流程图
图1 父进程流程图
图2 子进程P1流程图四、运行结果及说明
五、源代码
#include <stdio.h>
#include <sys/types.h> #include <stdlib.h>
#include <sys/stat.h> #include <fcntl.h>
#include <error.h>
#include <wait.h>
#include <unistd.h>
int main( ){
int pid1,pid2,pid3;
int fd[2];
char outpipe[60],inpipe[60];
pipe(fd);//创建一个管道
while ((pid1=fork( ))==-1);
printf("pid1=%d\n",pid1);
if(pid1==0){
printf("The Child process 1 is sending message!\n");
lockf(fd[1],1,0);//互斥
sprintf(outpipe,"This is the child 1 process's message!\n");
write(fd[1],outpipe,60);
sleep(1);//自我阻塞1秒,让出机会执行下一个进程,增加并发度
lockf(fd[1],0,0);
exit(0);
}
else{
while((pid2=fork( ))==-1);
printf("pid2=%d\n",pid2);
if(pid2==0){
printf("The Child process 2 is sending message!\n");
lockf(fd[1],1,0);
sprintf(outpipe,"This is the child 2 process's message!\n");
write(fd[1],outpipe,60);
sleep(1);
lockf(fd[1],0,0);
exit(0);
}
else{
while((pid3=fork( ))==-1);
printf("pid3=%d\n",pid3);
if(pid3==0){
printf("The Child process 3 is sending message!\n");
lockf(fd[1],1,0);
sprintf(outpipe,"This is the child 3 process's message!\n");
write(fd[1],outpipe,60);
sleep(1);
lockf(fd[1],0,0);
exit(0);
}
else{
wait(0);//同步
read(fd[0],inpipe,60);
printf("\n%s",inpipe);
wait(0);
read(fd[0],inpipe,60);
printf("%s\n",inpipe);
wait(0);
read(fd[0],inpipe,60);
printf("%s\n",inpipe);
exit(0);
}
}
}
return 0;
}
六、回答问题
(1)指出父进程与两个子进程并发执行的顺序,并说明原因。
子进程先执行,然后父进程才执行。
这是由进程的同步机制决定的,因为只有子进程向管道中写入信息后,父进程才能读取;否则父进程自己调用wait()系统调用将自己阻塞,将处理机交由子进程。
(2)若不对管道加以互斥控制,会有什么后果?
管道进行互斥控制,是为防止两个子进程对管道资源进行争夺而产生信息丢失或覆盖。
如果不加控制,那么可能一个子进程写入的信息还没来得及被父进程读出,另一个子进程又先写入信息,那么之前的进程写入的信息将被覆盖,父进程也就读不到之前进程传递来的信息了。
(3)说明你是如何实现父子进程之间的同步的。
1、父进程读出之前确定管道中有数据,否则阻塞自己。
这一点很容一般到,通过系统调用wait()函数,即可以实现,当子进程结束时父进程才执行,那么此时管道中肯定已经有子进程写入的数据了。
2、子进程在写入之前要确定管道中的数据已经被父进程读出,否则不能写入或者阻塞自己。
实用标准
3、这可以通过进程间的互斥来间接的办到。
因为子进程间的互斥,所以每个子进程在执行开始都对管道pipe加锁,那么这样同时就只能有一个子进程向管道写入数据,并且子进程在向管道中写入数据后还要调用sleep()系统调用睡眠若干时间,那么这样就可以保证父进程能够从管道中读出数据。
然后下一子进程才能写入。
那么这样就保证了开头所说的子进程在写入之前要确定管道中的数据已经被父进程读出,否则不能写入或者阻塞自己。
文案大全。