实验三进程通信
操作系统实验三进程的管道通信
实验三进程的管道通信一、实验目的:(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),写出程序的运行结果并分析
实验代码:
#include<stdio.h>
main()
{ int x,fd[2];
char buf[30],s[30];
pipe(fd);
while ((x=fork())==-1);
if (x==0)
}
write(fe[1],s,30);
wait(0);
}
运行结果:
(3)阅读例2的程序,运行一次该程序,然后用ipcs命令查看系统中共享存储区的情况,再次执行该程序,再用ipcs命令查看系统中共享内存的情况,对两次的结果进行比较,并分析原因。最后用ipcrm命令删除自己建立的共享存储区。(有关ipcs和ipcrm介绍见后面一页)
addr=shmat(shmid,0,0);/*挂接,并得到共享区首地址*/
printf ("addr 0x%x\n",addr);
pint=(char *)addr;
for (i='a';i<='e';i++) *pint++=i;
pause();/*等待接收进程读*/
}
cleanup()
{
shmctl(shmid,IPC_RMID,0);
(2)每个同学登陆两个窗口,先在一个窗口中运行例3程序1(或者只登陆一个窗口,先在该窗口中以后台方式运行程序1),然后在另一个窗口中运行例3程序2,观察程序的运行结果并分析。运行结束后可以用ctrl+c结束程序1的运行。
(3)编写程序:使用系统调用shmget(),shmat(),shmdt(),shmctl(),编制程序。要求在父进程中生成一个30字节长的私有共享内存段。接下来,设置一个指向共享内存段的字符指针,将一串大写字母写入到该指针指向的存贮区。调用fork()生成子进程,让子进程显示共享内存段中的内容。接着,将大写字母改成小写,子进程修改共享内存中的内容。之后,子进程将脱接共享内存段并退出。父进程在睡眠5秒后,在此显示共享内存段中的内容(此时已经是小写字母)。
实验三_进程间通信 (1)
实验三线程控制和进程间通信一、实验目的通过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的长度限制,因此,采用阻塞型读写方式时,当管道已经写满时,写进程必须等待,直到读进程取走信息为止。
进程通讯管理实验报告(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)数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。
实验三进程间通信
实验三进程间通信实验三进程间通信UNIX/LINUX 系统的进程间通信机构(IPC)允许在任意进程间大批量地交换数据。
本实验的目的是了解和熟悉LINUX 支持的信号量机制、管道机制、消息通信机制及共享存储区机制。
(一)信号机制实验目的1、了解什么是信号2、熟悉LINUX 系统中进程之间软中断通信的基本原理实验内容1、编写程序:用fork( )创建两个子进程,再用系统调用signal( )让父进程捕捉键盘上来的中断信号(即按^c 键);捕捉到中断信号后,父进程用系统调用kill( )向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:Child process1 is killed by parent!Child process2 is killed by parent!父进程等待两个子进程终止后,输出如下的信息后终止:Parent process is killed!2、分析利用软中断通信实现进程同步的机理系统调用格式signal(sig,function)头文件为#include参数定义signal(sig,function)int sig;void (*func) ( )三、参考程序#include#include#includevoid waiting( ),stop( );int wait_mark;main( ){int p1,p2,stdout;while((p1=fork( ))= =-1); /*创建子进程p1*/if (p1>0){while((p2=fork( ))= =-1); /*创建子进程p2*/if(p2>0){wait_mark=1;signal(SIGINT,stop); /*接收到^c 信号,转stop*/ waiting( ); kill(p1,16); /*向p1 发软中断信号16*/kill(p2,17); /*向p2 发软中断信号17*/wait(0); /*同步*/wait(0);printf("Parent process is killed!\n");exit(0);}else{wait_mark=1;signal(17,stop); /*接收到软中断信号17,转stop*/ waiting( );lockf(stdout,1,0);printf("Child process 2 is killed by parent!\n");lockf(stdout,0,0);exit(0);}}else{wait_mark=1;signal(16,stop); /*接收到软中断信号16,转stop*/ waiting( );lockf(stdout,1,0);printf("Child process 1 is killed by parent!\n");lockf(stdout,0,0);exit(0);}}void waiting( ){while(wait_mark!=0);}void stop( ){wait_mark=0;}四、运行结果屏幕上无反应,按下^C 后,显示Parent process is killed!五、分析原因上述程序中,signal( )都放在一段程序的前面部位,而不是在其他接收信号处。
实验三、进程通信一 ——管道及共享内存
操作系统实验报告实验三、进程通信(一)——管道及共享存一、实验目的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()函数产生两个进程,首先开始执行子进程,关闭管道出口,通过管道入口向管道中写入容。
Lab3--进程间通信
进程间通信
一、实验目的
在本实验中,通过对生产者消费者算法的理解和实现,熟悉同步信号量以及互斥信号量的使用,并加深对进程间通信原理的理解。
二、实验内容
参考教材中的生产者消费者算法,创建5个进程,其中两个进程为生产者进程,3个进程为消费者进程。
要求如下:
1)一个生产者进程试图不断地在一个缓冲中写入大写字母,另一个生产者进程试图不断地在缓冲中写入小写字母。
2)3个消费者不断地从缓冲中读取一个字符并输出,其中一个消费者只消费小写字符,一个消费者只消费大写字母,而另一个消费者则无选择地消费任何产品,消费者要消费的产品没有时,消费者进程被阻塞。
注意缓冲的管理。
3)为了使得程序的输出易于看到结果,分别在生产者和消费者进程的合适的位置加入一些随机睡眠时间。
三、思考题
1. 如何实现共享存储区互斥访问,如果没有对缓冲区实现互斥访问,会发生什
么现象?
2. 当对缓冲区的操作有多把锁时,如何避免死锁情况的发生?
3. 能否用上一次的实验中用到的记录锁实现对单一资源互斥访问?如果能,请
给出具体实现。
4. 能否采用信号机制实现进程间的同步与互斥?。
操作系统实验三(进程通信)
暨南大学本科实验报告专用纸课程名称《操作系统原理实验》成绩评定实验项目名称进程通信指导教师戴红实验项目编号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所指的文件做各种锁定或解除锁定的动作。
进程通信实验报告
操作系统实验报告(三)进程通信专业:软件工程姓名:XXX班级:XXX学号:XXX指导老师:XXX2013/12/3实验三:进程通信一.实验目的加深对进程通信的理解。
熟悉消息通信机制、共享存储器通信机制,进一步认识其与信号量通信的区别。
二.实验内容1)编程实现基于消息缓冲队列机制的进程通信数据结构和通信原语(创建消息、发送消息、接收消息);2)最后编写主函数对所做工作进行测试三.实验步骤(1)任务分析:实现进程通信,需要建立创建消息函数、发送消息函数、接收消息函数,需要用到进程中的Send和Receive原语(2)程序设计:a.总体设计:创建两个windows窗体应用程序,分别用于发送消息和接收消息,可以采用C#实现。
b.具体实现①创建应用程序Sendmessage,在windows窗体上放置一个文本框输入要发送的消息,一个按钮控件,单击按钮控件发送消息,编辑ButtonOnclick()事件,来编辑发送消息函数,发送后弹出消息发送成功对话框。
②创建应用程序Receivemessage,在windows窗口上放置一个文本框用于接收消息,放置一个Button按钮,并编辑ButtonOnclick()事件,来编辑接收消息函数,成功后弹出成功接收对话框。
③程序中的发送接收需要用到系统中的函数,将在实验代码中给与提示。
(4)调试与测试实验结果:发送消息:接收消息:四.实验总结进程通信实验主要是通过通信原语机制创建消息发送函数和消息接收函数来模拟实现进程间的通信,在实验过程中,一些通信机制不是太明确,通过在网上查找资料以及和同学们交流,最终完成了进程通信实验,通过这次实验,我对进程间的通信原理多了更深一步的了解,为学习操作系统知识建立了良好的实践基础。
五.附录①发送消息函数源码:using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using System.Runtime.InteropServices;namespace WindowsFormsApplication1{public partial class Form1 : Form{public Form1(){InitializeComponent();}[DllImport("User32.dll", EntryPoint = "SendMessage")] private static extern int SendMessage(int hWnd,int Msg,int wParam,ref COPYDATASTRUCT lParam);[DllImport("User32.dll", EntryPoint = "FindWindow")] private static extern int FindWindow(string lpClassName, string lpWindowName);public struct COPYDATASTRUCT{public IntPtr dwData;public int cbData;[MarshalAs(UnmanagedType.LPStr)]public string lpData;}const int WM_COPYDATA = 0x004A;private void button1_Click(object sender, EventArgs e){Sent();MessageBox.Show("信息发送成功|", "提示?", MessageBoxButtons.OK);}private void Sent(){int WINDOW_HANDLER = FindWindow(null, @"接受信息");if (WINDOW_HANDLER != 0){byte[] sarr =System.Text.Encoding.Default.GetBytes(this.textBox1.Text);int len = sarr.Length;COPYDATASTRUCT cds;cds.dwData = (IntPtr)100;cds.lpData = this.textBox1.Text;cds.cbData = len + 1;SendMessage(WINDOW_HANDLER, WM_COPYDATA, 0, ref cds); } }}}②接收消息函数源码:using System;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using System.Runtime.InteropServices;namespace WindowsFormsApplication2{public partial class Form1 : Form{string message;public Form1(){InitializeComponent();}public struct COPYDATASTRUCT{public IntPtr dwData;public int cbData;[MarshalAs(UnmanagedType.LPStr)]public string lpData;}const int WM_COPYDATA = 0x004A;private void button1_Click(object sender, EventArgs e) {Receive();}private void Receive(){textBox1.Text += "收到信息为"+ message + Environment.NewLine;MessageBox.Show("成功接收!");}protected override void DefWndProc(refSystem.Windows.Forms.Message m){switch (m.Msg){case WM_COPYDATA:COPYDATASTRUCT mystr = new COPYDATASTRUCT();Type mytype = mystr.GetType();mystr = (COPYDATASTRUCT)m.GetLParam(mytype); message = mystr.lpData;break;default:base.DefWndProc(ref m);break;}}}}。
操作系统实验三进程的管道通信
操作系统实验三进程的管道通信操作系统中的进程通信是指进程之间通过一定机制进行信息传递和交换的过程。
而管道是常用的进程间通信(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]是管道的写端口,用于向管道写入数据。
实验3 进程通信
实验三进程通信
1.实验类型:设计性实验
2.实验目的:
了解和熟悉LINUX的管道通信、软中断通信、SOCKET通信等
3.实验内容:
练习一三个子进程和父进程的管道通信。
(必做)
编写一个程序,建立一个管道。
同时,父进程生成子进程P1,P2,P3这三个子进程分别向管道中写入消息(消息由键盘输入),父进程将消息读出。
练习二软中断一(必做)
编写一个程序循环输出“how are you?”,当键盘输入Ctrl+C时终止,当输出次数不超过5000次时在此过程中使用Ctrl+C不能中断显示,5000次后才能用Ctrl+C中断显示,然后输出“Byebye”.
练习三软中断二(选做)
使用软中断实现父子进程同步,父进程先输出A,然后子进程输出B。
练习四编程实现基于SOCKET的进程间通信,实现网络中不同终端间可相互通信。
(选做)
要求:分别编写服务器端和客户端两个程序(使用线程),编译后分别在不同终端运行程序,二者间可相互进行通信。
实验三_进程间的通信
本科实验报告专用纸课程名称操作系统原理成绩评定实验项目名称进程间的通信指导教师实验项目编号实验项目类型实验地点学生姓名学号学院系专业实验时间年月日上午~月日上午温度℃湿度一、实验目的和要求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:用来指明核心程序在队列没有数据的情况下所应采取的行动。
实验3 进程通信
准备知识
掌握Socket通信的基本概念和工作原理; 掌握必要的网络知识,如TCP协议。
实验原理
Socket
Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程 ,可以用来进行网络方面的程序设计与开发。Socket(套接字)是通 过标准的Unix文件描述符和其它程序通信的一个方法。Socket数据传 输是一种特殊的输入输出,Socket套接字也是一种文件描述符。 Socket也具有一个类似于打开文件的创建函数Socket( ),该函数返回 一个整型的Socket描述符,随后的建立连接、消息传输等操作都是对 该描述符进行操作的。每一个套接字都用一个半相关描述:{协议, 本地地址、本地端口}来表示;一个完整的套接字则用一个相关描述 :{协议,本地地址、本地端口、远程地址、远程端口}。每一个套接 字都有一个本地的由操作系统分配的唯一的套接字号。
Socket的三种类型
(1)流式Socket(SOCK_STREAM) 流式套接字提供可靠的、面向连接的通信流;它使用TCP协议, 从而保证了数据传输的正确性和顺序性。 (2)数据报Socket(SOCK_DGRAM) 数据报套接字定义了一种无连接的服务,数据通过相互独立的报 文进行传输,是无序的,并且不保证可靠性、无差错。它使用数据报协 议UDP。 (3)原始Socket 原始套接字允许对底层协议如IP或ICMP直接访问,它功能强大 但使用较为不便,主要用于一些协议的开发。
实验3 进程通信
实验内容1 管道通信 实验内容12 Socket通信
管道通信
实 实 准 实 实
验 验 备 验 验
目 内 知 原 指
的 容 识 理 导
实验目的
实验三 进程间通信和信号灯
实验三进程间通信和信号灯班级:姓名:学号:实验目的1.理解Linux关于进程通信的概念。
2.掌握通过无名管道PIPE进行进程间通信的方法。
3.巩固进程同步概念和实现进程同步的方法。
4.加深对生产者消费者问题的理解。
5.学会使用Linux 信号量控制系统调用(PV操作)。
实验内容编写一个程序,该程序主进程用来接受用户键盘输入的信息,子进程则将键盘输入的内容显示在屏幕上,该过程要求重复出现,直到用户使用ctrl+c终止程序运行。
该实验内容其实质也是生产者消费者的问题,即一个进程产生数据(由用户输入),另一个进程输出之前由用户输入的数据。
两个进程之间通过进程通信(IPC)技术来实现消息的传递,为了简化编码的复杂度,我们使用Linux中的管道技术(无名PIPE)实现进程间通信(有兴趣的同学,可以在完成后尝试使用共享内存的方式来进行进程间通信)。
我们要求使用PV操作对信号量进行控制,从而实现生产者进程和消费者进程之间合理有序的工作(进程同步问题的进一步深入理解)。
这里的PV操作,我们利用Linux系统提供的信号量系统调用来实现。
学习管道系统调用所需头文件 :#include<unistd.h>int pipe(intfiledes[2]); /*pipe()会建立管道,并将文件描述词由参数filedes数组返回。
*/ filedes[0]为管道里的读取端,所以pipe用read调用的filedes[1]则为管道的写入端。
ssize_t write(intfd, const void *buf, size_t count); /*像fd所指向的管道操作符(文件)写入数据*/第一个参数表示所要写入数据的文件操作符,这里为管道操作符。
第二个参数表示所要写入信息所在的缓存区。
第三个参数表示缓冲区中前多少个数据应该被写入文件fd中。
通常设定为缓冲区的大小。
例子: write(filedes[1], buf, sizeof(buf);ssize_t read(intfd, const void *buf, size_t count); /*读取fd所指向的管道操作符的数据到缓冲区buf中*/第一个参数表示所要读取数据的文件操作符,这里为管道操作符。
实验3进程通信
实验三进程通信学校:FJUT 学号:3131903229 班级:计算机1302 姓名:姜峰. 实验学时与类型学时:2,课外学时:自定实验类型:设计性实验. 实验目的了解Linux 的软中断、管道、消息队列、共享存储区等进程间通信方式。
. 实验内容1. 软中断通信机制(1) 请编写一个程序:循环输出“ how are you? ”,在按下Ctrl+C 后中断显示,输出Byebye! ”后退出程序。
源代码:#include <stdio.h>#include <signal.h>int flag = 1;void Soft_Interrupt(){ flag = 0;return;}int main(){signal( 2, Soft_Interrupt );while( flag ) {printf( "how are you?\n" ); }printf( "Byebye!" );return 0;} 运行结果截图:(2)使用软中断机制实现父子进程同步,父进程先输出A,然后子进程输出B。
源代码:#in elude <stdio.h>#in elude <uni std.h>#in elude <sig nal.h>int flag = 1;void Soft」nterrupt(){flag = 0;return;}int mai n(){int pid = fork();if( pid > 0 ){prin tf( "I am father:A\n");kill( pid, 10 );[root^locaIhos t [r DD l L 'l oca Lhcs t [root^loca Itios 1 J am fa I he r : A]am ch i Ld :B [root^'Iqca I tin s telse if( pid == 0 ){sig nal( 10, Soft 」nterrupt );while( flag ){sleep( 1 );}prin tf( "I am child:B\n");}else{printf( "EORROR!\n");return -1;} return 0;运行结果截图:lesl3]vi test3_l_2le s l3]4 cc -o les _2 te s I A_1 _2 . c./les l3_l_22. 管道机制(1)父子进程通过管道传送一串字符。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验三进程通信一.实验学时与类型学时:2,课外学时:自定实验类型:设计性实验二.实验目的了解Linux的软中断、管道、消息队列、共享存储区等进程间通信方式。
三.实验容1. 软中断通信机制(1) 请编写一个程序:循环输出“how are you?”,在按下Ctrl+C后中断显示,输出“Byebye!”后退出程序。
#include<signal.h>#include<stdio.h>int k=1;void int_func(int sig) //软中断处理函数{ k=0; }Int main(){ signal(SIGINT,int_func);//预置软中断信号处理函数While(k==1)Printf(“how are you?\n”);Printf(“byebye!”);}(2)使用信号机制实现父子进程同步,父进程先输出A,然后子进程输出B。
#include<signal.h>#include<stdio.h>int k=1;void func(int sig) { k=0; }main(){ int pid;pid=fork();if(pid>0){ printf(“A\n”);kill(pid,12);}else if(pid==0){ signal(12,func);while(k==1)sleep(1);printf(“B\n”);}}2. 管道机制(1) 父子进程通过管道传送一串字符。
要求:子进程随机从键盘输入一串字符,通过管道发给父进程,父进程从管道中将消息读出并显示出来。
#include<stdio.h>#include<unistd.h>main(){ int pid, fd[2] ;char outpipe[50], inpipe[50];pipe(fd);pid=fork();if (pid==0){Printf(“please input some message:\n”);Fgets(inpipe,sizeof(inpipe),stdin);write(fd[1],inpipe,50);}else if (pid>0);{ wait(0);Printf(“father get this message:\n”);read(fd[0],outpipe,50);printf(“%s\n”,outpipe);}}(2)父子进程通过管道互相发送字符串。
要求:子进程向父进程通过管道发送”I am child.”,父进程回送”I am father.”,父子进程将各自收到的字符串显示在屏幕上。
#inlcude<stdio.h>#include<unistd.h>#include<string.h>main(){ int pid, fd[2] ;char str1[50], str2[50];pipe(fd);pid=fork();if (pid==0){ strcpy(str1,”I’m child”);write(fd[1],str1,strlen(str1));Sleep(1);read(fd[0],str2,50);printf(“Child received: %s\n”,str2);}else if (pid>0){ read(fd[0],str1,50);printf(“Parent received:%s\n”,str1);strcpy(str2,”I’m father.”);write(fd[1],str2,strlen(str2));}}3. 消息队列机制(1) 父进程及其子进程通过一条消息队列互相传送数据。
#include<stdio.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>int msgqid,qid;struct msg{ long mtype;char mtext[256];}pmsg;cancelqueue(){ msgctl(msgqid,IPC_RMID,0);exit(0);}main(){ int pid;Pid=fork();If (pid>0){ msgqid=msgget(75, 0777);printf(“msg id: %d\n”,msgqid);pmsg.mtype=1;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);msgrcv(msgqid,&pmsg,256,getpid(),0);printf(“A:receive msg from %d\n",*((int *)pmsg.mtext)); }Else if(pid==0){ signal(2,cancelqueue);msgqid=msgget(75, 0777|IPC_CREAT);while(1){ msgrcv(msgqid,&pmsg,256,1,0);qid=*(int *)pmsg.mtext;printf(“B:receive msg from %d\n”,qid);pmsg.mtype=qid;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);}}}(2) 非父子进程之间实通过一条消息队列互相传递数据。
A进程:#include<stdio.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>struct msg{ long mtype;char mtext[256];}pmsg;main(){ int msgqid,pid;msgqid=msgget(75, 0777);printf(“msg id: %d\n”,msgqid);pmsg.mtype=1;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);msgrcv(msgqid,&pmsg,256,getpid(),0);printf(“A:receive msg from %d\n”,*((int *)pmsg.mtext)); }B进程:#include<stdio.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>int msgqid,pid;struct msg{ long mtype;char mtext[256];}pmsg;cancelqueue(){ msgctl(msgqid,IPC_RMID,0);exit(0);}main(){ signal(2,cancelqueue);msgqid=msgget(75, 0777|IPC_CREAT);while(1){ msgrcv(msgqid,&pmsg,256,1,0);pid=*(int *)pmsg.mtext;printf(“B:receive msg from %d\n”,pid);pmsg.mtype=pid;*((int *)pmsg.mtext)=getpid();msgsnd(msgqid,&pmsg,sizeof(int),0);}}4. 共享存机制(1) 编程实现基于共享存的进程间通信。
要求:进程A通过共享存将自己的进程号传递给进程B。
A:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int *)shmat(shmid, 0,0);*va=getpid();printf(“get A’s pid:%d\n”,*va);shmdt(va);}B:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int*)shmat(shmid, 0,0);printf(“A’s pid is :%d\n”,*va);shmdt(va);shmctl(shmid,IPC_RMID,0);}(2) 若要通过共享存实现进程A与进程B互送进程号,可怎样编程实现?A:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int *)shmat(shmid, 0,0);*va=getpid();printf(“get A’s pid:%d\n”,*va);Sleep(2);printf(“B’s pid is:%d\n”,*va)shmdt(va)}B:#include<stdio.h>#include<sys/shm.h>main(){ int shmid;int *va;shmid=shmget(22,sizeof(*va),0666|IPC_CREAT);va=(int*)shmat(shmid, 0,0);printf(“A’s pid is :%s\n”,*va);*va=getpid();printf(“get B’s pid:%d\n”,*va);shmdt(va);shmctl(shmid,IPC_RMID,0);}5. SOCKET进程通信(选做)编程实现基于SOCKET的进程间通信,通过网络实现进程之间数据通信。
要求:分别编写服务器端和客户端方程序,运行于不同终端,二者可相互进行通信。
Server:#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>int main(){int server_sockfd = -1;int client_sockfd = -1;int client_len = 0;struct sockaddr_in server_addr;struct sockaddr_in client_addr;//创建流套接字server_sockfd = socket(AF_INET, SOCK_STREAM, 0);//设置服务器接收的连接地址和监听的端口server_addr.sin_family = AF_INET;//指定网络套接字server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//接受所有IP地址的连接server_addr.sin_port = htons(9736);//绑定到9736端口//绑定(命名)套接字bind(server_sockfd,(struct sockaddr*)&server_addr, sizeof(server_addr));//创建套接字队列,监听套接字listen(server_sockfd, 5);//忽略子进程停止或退出信号signal(SIGCHLD, SIG_IGN);while(1){char ch = '\0';client_len = sizeof(client_addr);printf("Server waiting\n"); //接受连接,创建新的套接字client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_len);if(fork() == 0){//子进程中,读取客户端发过来的信息,处理信息,再发送给客户端read(client_sockfd, &ch, 1);sleep(5);ch++;write(client_sockfd, &ch, 1);close(client_sockfd);exit(0);}else{//父进程中,关闭套接字close(client_sockfd);}}}Client:#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdio.h>#include <stdlib.h>int main(){int sockfd = -1;int len = 0;struct sockaddr_in address;int result;char ch = 'A'; //创建流套接字sockfd = socket(AF_INET, SOCK_STREAM, 0); //设置要连接的服务器的信息address.sin_family = AF_INET;//使用网络套接字address.sin_addr.s_addr = inet_addr("127.0.0.1");//服务器地址address.sin_port = htons(9736);//服务器所监听的端口len = sizeof(address);//连接到服务器result = connect(sockfd, (struct sockaddr*)&address, len);if(result == -1){perror("ops:client\n");exit(1);}//发送请求给服务器write(sockfd, &ch, 1);//从服务器获取数据read(sockfd, &ch, 1);printf("char form server = %c\n", ch);close(sockfd);exit(0);}四.思考与总结(1) 请对比下列程序与实验1(1)在按下Ctrl+C之后的运行现象。