操作系统实验进程通信
- 格式:doc
- 大小:45.50 KB
- 文档页数:5
《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写入的字符输出。
实验四:进程同步实验一、实验任务:1、熟悉操作系统进程通信原理2、设计程序,实现共享内存、管道通信、消息通信二、实验原理:1、进程间通信的几种方法简介(1)消息队列:消息队列是消息的链接表,包括Posix消息队列systemV消息队列。
有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。
(2)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。
是针对其他通信机制运行效率较低而设计的。
往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
(3)无名管道(Pipe)及有名管道(named pipe):有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;无名管道可用于有亲缘关系的进程之间彼此的通信,进行通信时候必须有一定的机制保证对管道写和读的互斥:即在读是要关闭写的端口,而在写的时候也要保证读的一端是关闭的。
2、进程通信函数(1)消息队列有关系统调用函数a.创建消息队列使用msgget()函数:#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int flag) ;该函数成功调用返回消息队列标识符。
其中的key是关键字,可以由ftok()函数得到:key=ftok(“.”,’a’);其中”.”可以是任何目录,’a’是任意字符,即所有群组标识。
flag是标识,IPC_CREAT位表示创建,一般由服务器程序创建消息队列时使用。
如果是客户程序,必须打开现存的消息队列,必须不使用IPC_CREAT。
发送和接收的消息都必须使用一个类似msgbuf的结构表示,msgbuf结构定义如下:struct msgbuf{long mtype;char mtext[1];}上面的定义,消息内容只有一个字节,是不实用的,一般我们需要重新定义一个结构:struct amsgbuf{long mtype;char mtext[200];}其中的mtype都是消息类型。
一、实验目的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()函数删除消息队列。
暨南大学本科实验报告专用纸课程名称《操作系统原理实验》成绩评定实验项目名称进程通信指导教师戴红实验项目编号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所指的文件做各种锁定或解除锁定的动作。
2.编辑结果如下。
3.编译和运行程序。
4. 运行解释结果
父进程创建一个子进程和一个无名管道fd。
父进程wait(0)等待子进程的终止信号,子进程向管道写入信息“This is a message。
”然后终止,父进程收到终止信号后从管道读出信息并显示在屏幕上后结束。
2.编辑结果如下。
3.编译和运行程序。
4. 运行解释结果
父进程先创建一个子进程1,子进程1往管道fd里写入信息,并输出parent的信息,父进程接着有创造了一个子进程2,子进程2也往fd管道fd里写入信息,父进程wait(0)等待两个子进程结束信号,等两个子进程都结束后,输出管道里的信息。
实现了父子进程之间的管道通信。
1.编辑源程序。
2.编辑结果如下。
3.编译和运行程序。
4. 运行解释结果
发送进程将要发送的信息从键盘输入,每输入一行就作为一条信息发送,用“end”作为结
束的信息,存入共享的内存区。
接收进程从信息队列逐个取出信息并显示输出。
1.编辑源程序。
2.编辑结果如下。
3.编译和运行程序。
4. 运行解释结果
发送进程将要发送的信息从键盘输入,每输入一行就作为一条信息发送,用“end”作为结束的信息,存入信息缓冲区。
接收进程从信息队列逐个取出信息并显示输出。
操作系统实验报告(三)进程通信专业:软件工程姓名: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;}}}}。
对观察到的内容做详细记录分析, 并写出实验报告。
对观察到的内容做详细记录分析,并写出实验报告。
四、实验过程与分析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所指示的缓冲区中。
进程通信(一)1 .实验目的学习如何利用管道机制、共享存储区机制进行进程间的通信,并加深对上述通信机制的理解。
2 .实验内容(1) 了解系统调用pipe()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程。
(2) 编写一段程序,使其用管道来实现父子进程之间的进程通信。
子进程向父进程发送自己的进程标识符,以及字符串“is sending a message to parent ! ”。
父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。
(3) 编写一段程序,使其用共享存储区来实现父子进程之间的进程通信。
父进程创建一个长度为512 字节的共享内存空间,显示写入该共享内存的数据;子进程将共享内存也附加到自己的地址空间,并向共享内存中写入数据。
3 .实验步骤(1) 了解系统调用pipe()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程。
pipe()创建一条管道进行信息传输。
shmget()得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符shmat()连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问shmdt()用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存shmctl()共享内存管理,完成对共享内存的控制(2) 编写一段程序,使其用管道来实现父子进程之间的进程通信。
子进程向父进程发送自己的进程标识符,以及字符串“is sending a message to parent ! ”。
父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。
程序代码:#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<unistd.h>int main(){int pid1,pid2;int fd[2];char out[512],in[512];pipe(fd);pid1=fork();if(pid1==0){sprintf(out,"%d is sending a message to parent!\n",getpid());printf("%s",out);write(fd[1],out,sizeof(out));}else{read(fd[0],in,sizeof(out));printf("%s",in);}return 0;}程序截图:运行结果:(3) 编写一段程序,使其用共享存储区来实现父子进程之间的进程通信。
实验报告实验题目姓名:学号:课程名称:操作系统实验所在学院:信息科学与工程学院专业班级:计算机任课教师:五、实验数据(现象)处理分析信号机制实验建立文件和可执行文件:信号机制实验运行结果:屏幕上无反应,按下^C 后,显示Parent process is killed!进程的管道通信可执行文件:管道通信实验运行结果:延迟5 秒后显示child 1 process is sending message!再延迟5 秒child 2 process is sending message!附加问题:在不修改程序的情况下要输出期望的结果,可以单独向父进程发送SIGINT 信号,这样即可避免子进程由于收到SIGINT 信号执行默认操作而自我终止,具体实现方法:(该实验中程序名为:demo2)首先让程序在后台运行,命令:./demo2&执行该命令后,会在后台生成3 个进程,使用ps 命令可以查看到它们的PID (相对小的PID 应该为父进程的PID,原因是创建时间相对早)。
然后向后台的父进程发送SIGINT 信号,命令:kill –SIGINT 28664 (其中28664为父进程的PID)运行结果如下所示:进程通信消息机制实验可执行文件:进程通信消息机制实验运行结果1:进程通信消息机制实验运行结果2:六、实验结论通过实验了解和熟悉了LINUX 支持的信号量机制、管道机制、消息通信机制及共享存储区机制的基本原理和基本概念。
对信号和中断有了进一步的理解,能够分辨出两者的区别和相似点。
观察实验现象知道了信号的发送方式和处理方式。
掌握了信号的发送,是指由发送进程把信号送到指定进程的信号域的某一位上。
如果目标进程正在一个可被中断的优先级上睡眠,核心便将它唤醒,发送进程就此结束。
一个程可能在其信号域中有多个位被置位,代表有多种类型的信号到达,但对于一类信号,进程却只能记住其中的某一个。
通过本次实验最终目的还是全面了解进程的各种机制以及处理方法。
(操作系统原理和linux操作系统相结合的实验)实验二进程的通信一实验目的1 学会使用vi编辑器编辑C语言程序2 学会Linux环境下gcc的使用3 学会调试工具GDB的使用二实验原理1 利用linux提供的进程通信的系统调用设计进程通信程序,加深对进程通信概念的理解。
2 体会进程通信的方法和效果。
三实验环境PC机1台,Windows操作系统和其上的虚拟Linux操作系统。
四实验步骤1.管道通信(1)编写一个程序。
父进程创建一个子进程和一个无名管道fd,由子进程向管道写入信息“This is a message”,然后终止执行;父进程接收到子进程终止信号后从管道中读出并显示信息后结束。
#include<stdio.h>#include<unistd.h>main(){int p1,fd[2];char outpipe[50]; //定义读缓冲区char inpipe[50]="This is a message!"; //定义写缓冲区pipe(fd); //创建无名管道fdwhile((p1=fork())==-1);if (p1==0) //子进程返回{write(fd[1],inpipe,50); //写信息到管道exit(0);}else //父进程返回{wait(0); //等待子进程终止read(fd[0],outpipe,50); //从管道读信息到读缓冲区printf("%s\n",outpipe); //显示读到的信息exit(0);}}(2)父进程创建两个子进程,父子进程之间利用管道进行通信。
要求能显示父进程、子进程各自的信息,体现通信效果。
(源程序pipe_1.c)#include<stdio.h>main(){int I,r,j,k,l,p1,p2,fd[2];char buf[50],s[50];pipe(fd);while((p1=fork())==-1);if(p1==0){lockf(fd[1],1,0);sprintf(buf,"Child process p1 is sending message!\n");printf("Child process p1!\n");write(fd[1],buf,50);lockf(fd[1],0,0);sleep(5);j=getpid();k=getppid();printf("p1 %d is weakup.My parent process id is %d.\n",j,k);exit(0);}else{while((p2=fork())==-1);if(p2==0){lockf(fd[1],1,0);sprintf(buf,"Child process p2 is sending message!\n");printf("Child process p2!\n");write(fd[1],buf,50);lockf(fd[1],0,0);sleep(5);j=getpid();k=getppid();printf("p2 %d is weakup.My parent process id is %d.\n",j,k);exit(0);}else{I=getpid();wait(0);if(r=read(fd[0],s,50)==-1)printf("can’t read pip e.");elseprintf("Parent %d:%s\n",l,s);wait(0);if(r=read(fd[0],s,50)==-1)pr intf("can’t read pipe");elseprintf ( "Parent %d:%s\n",l,s);exit(0);}}}结果:2.共享内存通信。
西安电子科技大学《操作系统原理》实验报告题目:进程通信实验报告班级: 030912姓名:王增祥学号: 03091168实验内容补充说明:一、分析和设计1.理论分析每个Windows进程都是由一个执行体进程块(EPROCESS)表示。
API函数CreatProcess 可以创建进程,采用管道技术可以实现进程间的相互通信。
建立pipe,进程以及其子进程就可以对该管道进程读写共享,管道读写操作利用,write、read、close进行。
父进程利用pipe 发送消息,子进程利用该pipe接收父进程发来的消息;子进程利用管道向父进程发送应答,父进程利用该pipe接受应答。
2.总体设计1、利用CreatProcess函数创建进程。
2、创建管道,实现进程间的通信二、详细实现1、创建界面,采用Botton、列表框等控件创建父子界面如下图:父进程界面:子进程界面:其中父进程各个空间创建类向导如图:子进程创建类向导如图:2.父进程编写(1)创建管道:(2)创建子进程:(3)消息发送(4)消息接受3.子进程编写(1)发送消息(2)读消息三、实验结果点击创建子进程按钮:在创建子进程之后进行进程间的通信如下图四、心得体会1、从试验的角度了解了进程间是怎样利用管道进行通信的,了解了进程间通信的实际过程2、进一步掌握了MFC的初步编程技巧,知道了怎样调试程序。
3进一步了解了,API函数的应用,明白了怎样进行界面编程。
4、进一步熟悉了在进行进程通信的编写过程中的各个细节。
六、附录Process_Father.cpp#include "stdafx.h"#include "Process_Father.h" //包含已编写的Process_Father.h头文件#include "Process_FatherDlg.h" //包含已编写的Process_FatherDlg.h头文件//进行宏定义#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif//创建父进程BEGIN_MESSAGE_MAP(CProcess_FatherApp, CWinApp)//{{AFX_MSG_MAP(CProcess_FatherApp)// NOTE - the ClassWizard will add and remove mapping macros here.// DO NOT EDIT what you see in these blocks of generated code!//}}AFX_MSGON_COMMAND(ID_HELP, CWinApp::OnHelp)END_MESSAGE_MAP()// CProcess_FatherApp constructionCProcess_FatherApp::CProcess_FatherApp(){// TODO: add construction code here,// Place all significant initialization in InitInstance}// The one and only CProcess_FatherApp objectCProcess_FatherApp theApp;// CProcess_FatherApp initializationBOOL CProcess_FatherApp::InitInstance(){AfxEnableControlContainer();#ifdef _AFXDLLEnable3dControls(); // Call this when using MFC in a shared DLL #elseEnable3dControlsStatic(); // Call this when linking to MFC statically #endifCProcess_FatherDlg dlg;m_pMainWnd = &dlg;int nResponse = dlg.DoModal();if (nResponse == IDOK){// TODO: Place code here to handle when the dialog is// dismissed with OK}else if (nResponse == IDCANCEL){// TODO: Place code here to handle when the dialog is// dismissed with Cancel}// Since the dialog has been closed, return FALSE so that we exit the// application, rather than start the application's message pump.return FALSE;}Process_FatherDlg.cpp// Process_FatherDlg.cpp : implementation file//#include "stdafx.h"#include "Process_Father.h"#include "Process_FatherDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}void CAboutDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////// // CProcess_FatherDlg dialogCProcess_FatherDlg::CProcess_FatherDlg(CWnd* pParent /*=NULL*/) : CDialog(CProcess_FatherDlg::IDD, pParent){//{{AFX_DATA_INIT(CProcess_FatherDlg)//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CProcess_FatherDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CProcess_FatherDlg)DDX_Control(pDX, IDC_BT_CreateChildProcess, m_BT_CreateChildProcess);DDX_Control(pDX, IDC_Send, m_Send);DDX_Control(pDX, IDC_LISTBOX_Record, m_LISTBOX_Record);DDX_Control(pDX, IDC_EDIT_Message, m_EDIT_Message);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CProcess_FatherDlg, CDialog)//{{AFX_MSG_MAP(CProcess_FatherDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BT_CreateChildProcess, OnBTCreateChildProcess)ON_BN_CLICKED(IDC_Send, OnSend)//}}AFX_MSG_MAPON_MESSAGE(WM_CHILD_SEND,OnReceiveMsg)END_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////// // CProcess_FatherDlg message handlersBOOL CProcess_FatherDlg::OnInitDialog(){CDialog::OnInitDialog();// Add "About..." menu item to system menu.// IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialogSetIcon(m_hIcon, TRUE); // Set big iconSetIcon(m_hIcon, FALSE); // Set small icon// TODO: Add extra initialization herereturn TRUE; // return TRUE unless you set the focus to a control}void CProcess_FatherDlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID, lParam);}}// If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework.void CProcess_FatherDlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}// The system calls this to obtain the cursor to display while the user drags // the minimized window.HCURSOR CProcess_FatherDlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}void CProcess_FatherDlg::OnBTCreateChildProcess(){//创建管道SECURITY_ATTRIBUTES sa;sa.nLength=sizeof(SECURITY_ATTRIBUTES);sa.lpSecurityDescriptor=NULL;sa.bInheritHandle=TRUE;::CreatePipe(&hPipeRead,&hPipeWrite,&sa,0);::CreatePipe(&hPipeRead2,&hPipeWrite2,&sa,0);//创建子进程STARTUPINFO StartupInfo;memset(&StartupInfo,0,sizeof(STARTUPINFO)) ;StartupInfo.cb=sizeof(STARTUPINFO);StartupInfo.dwFlags=STARTF_USESTDHANDLES;StartupInfo.hStdInput=hPipeRead;StartupInfo.hStdOutput=hPipeWrite;StartupInfo.hStdError=GetStdHandle(STD_ERROR_HANDLE);PROCESS_INFORMATION ProcessInfo;::CreateProcess("Process_Child.exe",NULL,NULL,NULL,TRUE,0,NULL,NULL,&Startu pInfo,&ProcessInfo);m_BT_CreateChildProcess.EnableWindow(FALSE);}void CProcess_FatherDlg::OnSend(){CString str;char ss[20]="Father:";m_EDIT_Message.GetWindowText(str);DWORD dwWritten;if(!WriteFile(hPipeWrite,str,40,&dwWritten,NULL)){MessageBox(TEXT("写错误"),"警告",MB_OK|MB_ICONWARNING);}CString strWinName = "Process_Child";CWnd *pWnd=CWnd::FindWindow(NULL,strWinName);if(pWnd){pWnd->SendMessage(WM_FATHER_SEND,0,0);strcat(ss,str);m_LISTBOX_Record.InsertString(-1,ss);m_EDIT_Message.SetWindowText("");}else{MessageBox("没有发现子进程","错误");}}void CProcess_FatherDlg::OnReceiveMsg(WPARAM wParam,LPARAM lParam){DWORD dwRead;TCHAR s[40];HANDLE hPipeRead2;hPipeRead2=GetStdHandle(STD_INPUT_HANDLE);if(!ReadFile(hPipeRead,s,40,&dwRead,NULL)){MessageBox(TEXT("读错误!"),"警告",MB_OK|MB_ICONWARNING);}char str[60]="Child: ";strcat(str,s);m_LISTBOX_Record.InsertString(-1,str);}Process_Father.h// Process_Father.h : main header file for the PROCESS_FATHER application//#if !defined(AFX_PROCESS_FATHER_H__1F9659A2_2B93_4C1E_89C5_5A88971D3DDA__INCLUD ED_)#define AFX_PROCESS_FATHER_H__1F9659A2_2B93_4C1E_89C5_5A88971D3DDA__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#ifndef __AFXWIN_H__#error include 'stdafx.h' before including this file for PCH#endif#include "resource.h" // main symbols///////////////////////////////////////////////////////////////////////////// // CProcess_FatherApp:// See Process_Father.cpp for the implementation of this class//class CProcess_FatherApp : public CWinApp{public:CProcess_FatherApp();// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CProcess_FatherApp)public:virtual BOOL InitInstance();//}}AFX_VIRTUAL// Implementation//{{AFX_MSG(CProcess_FatherApp)// NOTE - the ClassWizard will add and remove member functions here.// DO NOT EDIT what you see in these blocks of generated code !//}}AFX_MSGDECLARE_MESSAGE_MAP()};///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif// !defined(AFX_PROCESS_FATHER_H__1F9659A2_2B93_4C1E_89C5_5A88971D3DDA__INCLUDE D_)Process_FatherDlg.h// Process_FatherDlg.h : header file//#if !defined(AFX_PROCESS_FATHERDLG_H__69E2942A_7A5F_413F_B4A3_AFB8C1F51DFE__INC LUDED_)#defineAFX_PROCESS_FATHERDLG_H__69E2942A_7A5F_413F_B4A3_AFB8C1F51DFE__INCLUDED_#define WM_FATHER_SEND WM_USER+100#define WM_CHILD_SEND WM_USER+101#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000///////////////////////////////////////////////////////////////////////////// // CProcess_FatherDlg dialogclass CProcess_FatherDlg : public CDialog{// Constructionpublic:CProcess_FatherDlg(CWnd* pParent = NULL); // standard constructor// Dialog Data//{{AFX_DATA(CProcess_FatherDlg)enum { IDD = IDD_PROCESS_FATHER_DIALOG };CButton m_BT_CreateChildProcess;CButton m_Send;CListBox m_LISTBOX_Record;CEdit m_EDIT_Message;//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CProcess_FatherDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL// Implementationprotected:HICON m_hIcon;// Generated message map functions//{{AFX_MSG(CProcess_FatherDlg)virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();afx_msg void OnReceiveMsg(WPARAM wParam, LPARAM lParam);afx_msg void OnBTCreateChildProcess();afx_msg void OnSend();//}}AFX_MSGDECLARE_MESSAGE_MAP()private:HANDLE hPipeWrite2;HANDLE hPipeRead2;HANDLE hPipeWrite;HANDLE hPipeRead;};//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before theprevious line.#endif// !defined(AFX_PROCESS_FATHERDLG_H__69E2942A_7A5F_413F_B4A3_AFB8C1F51DFE__INCL UDED_)子进程代码Process_Child.cpp// Process_Child.cpp : Defines the class behaviors for the application.//#include "stdafx.h"#include "Process_Child.h"#include "Process_ChildDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CProcess_ChildAppBEGIN_MESSAGE_MAP(CProcess_ChildApp, CWinApp)//{{AFX_MSG_MAP(CProcess_ChildApp)// NOTE - the ClassWizard will add and remove mapping macros here.// DO NOT EDIT what you see in these blocks of generated code!//}}AFX_MSGON_COMMAND(ID_HELP, CWinApp::OnHelp)END_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////// // CProcess_ChildApp constructionCProcess_ChildApp::CProcess_ChildApp(){// TODO: add construction code here,// Place all significant initialization in InitInstance}///////////////////////////////////////////////////////////////////////////// // The one and only CProcess_ChildApp objectCProcess_ChildApp theApp;///////////////////////////////////////////////////////////////////////////// // CProcess_ChildApp initializationBOOL CProcess_ChildApp::InitInstance(){AfxEnableControlContainer();// Standard initialization// If you are not using these features and wish to reduce the size// of your final executable, you should remove from the following// the specific initialization routines you do not need.#ifdef _AFXDLLEnable3dControls(); // Call this when using MFC in a shared DLL #elseEnable3dControlsStatic(); // Call this when linking to MFC statically #endifCProcess_ChildDlg dlg;m_pMainWnd = &dlg;int nResponse = dlg.DoModal();if (nResponse == IDOK){// TODO: Place code here to handle when the dialog is// dismissed with OK}else if (nResponse == IDCANCEL){// TODO: Place code here to handle when the dialog is// dismissed with Cancel}// Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump.return FALSE;}Process_ChildDlg.cpp// Process_ChildDlg.cpp : implementation file//#include "stdafx.h"#include "Process_Child.h"#include "Process_ChildDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App Aboutclass CAboutDlg : public CDialog{public:CAboutDlg();// Dialog Data//{{AFX_DATA(CAboutDlg)enum { IDD = IDD_ABOUTBOX };//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CAboutDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL// Implementationprotected://{{AFX_MSG(CAboutDlg)//}}AFX_MSGDECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD){//{{AFX_DATA_INIT(CAboutDlg)//}}AFX_DATA_INIT}void CAboutDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CAboutDlg)//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)//{{AFX_MSG_MAP(CAboutDlg)// No message handlers//}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////// // CProcess_ChildDlg dialogCProcess_ChildDlg::CProcess_ChildDlg(CWnd* pParent /*=NULL*/): CDialog(CProcess_ChildDlg::IDD, pParent){//{{AFX_DATA_INIT(CProcess_ChildDlg)//}}AFX_DATA_INIT// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CProcess_ChildDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CProcess_ChildDlg)DDX_Control(pDX, IDC_Send, m_Send);DDX_Control(pDX, IDC_LISTBOX_Record, m_LISTBOX_Record);DDX_Control(pDX, IDC_EDIT_Message, m_EDIT_Message);//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CProcess_ChildDlg, CDialog)//{{AFX_MSG_MAP(CProcess_ChildDlg)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_Send, OnSend)//}}AFX_MSG_MAPON_MESSAGE(WM_FATHER_SEND,OnReceiveMsg)END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CProcess_ChildDlg message handlersBOOL CProcess_ChildDlg::OnInitDialog(){CDialog::OnInitDialog();// Add "About..." menu item to system menu.// IDM_ABOUTBOX must be in the system command range.ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != NULL){CString strAboutMenu;strAboutMenu.LoadString(IDS_ABOUTBOX);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}// Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialogSetIcon(m_hIcon, TRUE); // Set big iconSetIcon(m_hIcon, FALSE); // Set small icon// TODO: Add extra initialization herereturn TRUE; // return TRUE unless you set the focus to a control}void CProcess_ChildDlg::OnSysCommand(UINT nID, LPARAM lParam){if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialog::OnSysCommand(nID, lParam);}// If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework.void CProcess_ChildDlg::OnPaint(){if (IsIconic()){CPaintDC dc(this); // device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}// The system calls this to obtain the cursor to display while the user drags // the minimized window.HCURSOR CProcess_ChildDlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}void CProcess_ChildDlg::OnSend(){char ss[20]="Child:";CString str;m_EDIT_Message.GetWindowText(str);DWORD dwWritten;hPipeWrite=GetStdHandle(STD_OUTPUT_HANDLE);if(!WriteFile(hPipeWrite,str,40,&dwWritten,NULL)) {MessageBox(TEXT("写错误"),"警告",MB_OK|MB_ICONWARNING);}CString strWinName = "Process_Father";CWnd *pWnd=CWnd::FindWindow(NULL,strWinName);if(pWnd){pWnd->SendMessage(WM_CHILD_SEND,0,0);strcat(ss,str);m_LISTBOX_Record.InsertString(-1,ss);m_EDIT_Message.SetWindowText("");}else{MessageBox("没有发现父进程","错误");}void CProcess_ChildDlg::OnReceiveMsg(WPARAM wParam,LPARAM lParam){DWORD dwRead;char s[40];HANDLE hPipeRead;hPipeRead=GetStdHandle(STD_INPUT_HANDLE);if(!ReadFile(hPipeRead,s,40,&dwRead,NULL)){MessageBox(TEXT("读错误!"),"警告",MB_OK|MB_ICONWARNING);}char str[60]="Father: ";strcat(str,s);m_LISTBOX_Record.InsertString(-1,str);}Process_Child.h// Process_Child.h : main header file for the PROCESS_CHILD application//#if !defined(AFX_PROCESS_CHILD_H__7416C60C_DD56_40CC_BD28_3DA310873DE7__INCLUDE#define AFX_PROCESS_CHILD_H__7416C60C_DD56_40CC_BD28_3DA310873DE7__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000#ifndef __AFXWIN_H__#error include 'stdafx.h' before including this file for PCH#endif#include "resource.h" // main symbols///////////////////////////////////////////////////////////////////////////// // CProcess_ChildApp:// See Process_Child.cpp for the implementation of this class//class CProcess_ChildApp : public CWinApp{public:CProcess_ChildApp();// Overrides// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CProcess_ChildApp)public:virtual BOOL InitInstance();//}}AFX_VIRTUAL// Implementation//{{AFX_MSG(CProcess_ChildApp)// NOTE - the ClassWizard will add and remove member functions here.// DO NOT EDIT what you see in these blocks of generated code !//}}AFX_MSGDECLARE_MESSAGE_MAP()};///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before theprevious line.#endif// !defined(AFX_PROCESS_CHILD_H__7416C60C_DD56_40CC_BD28_3DA310873DE7__INCLUDED _)Process_ChildDlg.h// Process_ChildDlg.h : header file//#if !defined(AFX_PROCESS_CHILDDLG_H__01C41D47_4973_4DCB_84FC_4B7C5A6C584A__INCL UDED_)#define AFX_PROCESS_CHILDDLG_H__01C41D47_4973_4DCB_84FC_4B7C5A6C584A__INCLUDED_ #define WM_FATHER_SEND WM_USER+100#define WM_CHILD_SEND WM_USER+101#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000///////////////////////////////////////////////////////////////////////////// // CProcess_ChildDlg dialogclass CProcess_ChildDlg : public CDialog{// Constructionpublic:CProcess_ChildDlg(CWnd* pParent = NULL); // standard constructor// Dialog Data//{{AFX_DATA(CProcess_ChildDlg)enum { IDD = IDD_PROCESS_CHILD_DIALOG };CButton m_Send;CListBox m_LISTBOX_Record;CEdit m_EDIT_Message;//}}AFX_DATA// ClassWizard generated virtual function overrides//{{AFX_VIRTUAL(CProcess_ChildDlg)protected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL// Implementationprotected:HICON m_hIcon;// Generated message map functions//{{AFX_MSG(CProcess_ChildDlg)virtual BOOL OnInitDialog();afx_msg void OnSysCommand(UINT nID, LPARAM lParam);afx_msg void OnPaint();afx_msg HCURSOR OnQueryDragIcon();afx_msg void OnReceiveMsg(WPARAM wParam, LPARAM lParam);afx_msg void OnSend();//}}AFX_MSGDECLARE_MESSAGE_MAP()private:HANDLE hPipeWrite;};//{{AFX_INSERT_LOCATION}}// Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif// !defined(AFX_PROCESS_CHILDDLG_H__01C41D47_4973_4DCB_84FC_4B7C5A6C584A__INCLU DED_)。
进程通信(实验二)【实验目的】:掌握用邮箱方式进行进程通信的方法,并通过设计实现简单邮箱理解进程通信中的同步问题以及解决该问题的方法。
【实验原理】:邮箱机制类似于日常使用的信箱。
对于用户而言使用起来比较方便,用户只需使用send()向对方邮箱发邮件receive()从自己邮箱取邮件,send()和receive()的内部操作用户无需关心。
因为邮箱在内存中实现,其空间有大小限制。
其实send()和receive()的内部实现主要还是要解决生产者与消费者问题。
【实验内容】:进程通信的邮箱方式由操作系统提供形如send()和receive()的系统调用来支持,本实验要求学生首先查找资料了解所选用操作系统平台上用于进程通信的系统调用具体形式,然后使用该系统调用编写程序进行进程间的通信,要求程序运行结果可以直观地体现在界面上。
在此基础上查找所选用操作系统平台上支持信号量机制的系统调用具体形式,运用生产者与消费者模型设计实现一个简单的信箱,该信箱需要有创建、发信、收信、撤销等函数,至少能够支持两个进程互相交换信息,比较自己实现的信箱与操作系统本身提供的信箱,分析两者之间存在的异同。
实验背景介绍进程间通信有如下目的:数据的传输,共享数据,通知事情,资源共享,进程控制。
进程间的通信机制(IPC),就是多进程相互通信,交换信息的方法。
Linux IPC机制包括,信号和管道是其中的两个,还支持传统的UNIX SYSTM-V 的IPC 机制。
信号主要用来通知进程异步事情的发生,最初信号设计的目的是为了处理错误,他们也用来作为最基本的IPC机制。
管道是单向的,先进先出,先入先出,无结构的,固定大小的数据流。
UNIX System V 机制中的三种进程间通信机制,它们是:消息队列:用于进程之间传递分类的格式化数据信号量:用于通信之间的同步控制。
信号量通常与共享存储器方式一起使用。
共享内存:使不同进程通过共享彼此的虚拟空间而达到相互对共享区操作和数据通信。
它们之间有一个共同的特点,就是它们使用相同的认证方法,一个进程只有通过系统调用想内核传递一个唯一的引用标识符才能访问这些资源。
实验环境: ubuntu linux 操作系统实验原理分析:进程A 和进程B 共享内存C和D,并通过用P,V原理来控制它们对共享内存的读写。
共享内存通过PV控制读写。
信号量S0,S1,S2,S3 其中S0,S1控制C,S2,S3控制D。
其中S0表示内存中有几个信息,S1表示内存还可以存几个信息。
同理可得S2,S3.PV 简略图:进程A:发送信息......P(S1)Send ()V(S0)……接受消息……P(S2)Receive()V(S3)…….. 进程B:发送信息......P(S3)Send ()V(S2)……接受消息……P(S0)Receive()V(S1)……..函数调用分析:共享内存的创建,读,写,删除相当于信箱的创建,收信,发信,撤销等。
共享内存区域是被多个进程共享的一部分物理内存,进程可以把这些区域映射到它们地址空间的任一适合的虚拟地址范围。
这些地址范围对每一个进程来说都是不同的,映射后这些区域就可以像任何其他内存位置那样被访问,而不需要对它们使用读写调用。
进程向共享内存中写入数据,那么这个区域的所有进程可以立即看见共享区的新内容。
shmget(key_t key, size_t size, int shmflg);key标识共享内存的键值: 0/IPC_PRIVATE。
当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;如果key的取值为0,而参数shmflg中设置了IPC_PRIVATE这个标志,则同样将创建一块新的共享内存。
size是要建立共享内存的长度。
shmflg主要和一些标志有关。
其中有效的包括IPC_CREAT和IPC_EXCL,它们的功能与open()的O_CREAT和O_EXCL相当。
IPC_CREAT 如果共享内存不存在,则创建一个共享内存,否则打开操作。
IPC_EXCL 只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。
成功返回共享内存的标识符;不成功返回-1,errno储存错误原因。
例如:shmid=shmget(SHMKEY,256,IPC_CREAT|0600);创建了一个key=SHMKEY,大小为256的共享内存。
并把值给了shmid.shmat( int shmid , char *shmaddr , int shmflag );shmat()是用来允许本进程访问一块共享内存的函数。
int shmid是那块共享内存的ID。
char *shmaddr是共享内存的起始地址int shmflag是本进程对该内存的操作模式。
如果是SHM_RDONLY的话,就是只读模式。
其它的是读写模式成功时,这个函数返回共享内存的起始地址。
失败时返回-1例如:addr=(char *) shmat(shmid,NULL,0);内存地址映射把id为shmid共享内存的首地址给了addr,因此我们可以通过addr来访问共享内存,相当于,我们知道了数组的首地址,然后在对数组进行操作一样。
shmdt(Shared Memory Detach)函数与该共享内存块脱离。
将由shmat 函数返回的地址传递给这个函数。
成功共时返回0,不成功返回1,注意共享内存并未删除它,只是使该共享进程当前,进程不再可用。
如果当释放这个内存块的进程是最后一个使用该内存块的进程,则这个内存块将被删除。
例如:shmdt(addr);我们有了共享内存的首地址之后,对共享内存的读写就相当于对一个数组的读写。
写:strcpy(addr,"linux"); 就把linux字符放进了共享内存。
读:printf(“%s\n”,addr);综上所得,我们就很容易理解共享内存的一些操作;例:pid=shmget(Key,buffersize,IPC_CREAT|0600);//创建共享内存char *addr;addr=(char *)shmat(pid,NULL,0);//映射首地址strcpy(addr," This is the message which the parent have sent!");//写共享内存shmdt(addr);//释放共享内存信号量:是为了控制进程对资源的使用而发明的。
信号量是具有整数值的对象,它的工作原理如下;它支持两种原子操作P和V,P操作减少信号量的值,如果某一个信号量的值小于0,则操作阻塞,V操作增加信号量的值,如果结果值大于或等于0,V操作就要唤醒一个等待进程。
想要获得资源时使用P操作,每次请求成功,它都要减少信号量的值,信号量的值减至0时,下一个P操作将被阻塞,释放资源的时候使用V操作,它增加信号量的值,同时唤醒被阻塞的进程。
semget( semkey, count, flag);其中semkey 和flag 类似于建立消息和共享存储区域,semkey是用户指定的关键字,count 是指定信号量数组的长度。
Semid=(senkey ,4,0777|IPC_CREAT);创建了一个关键字为semkey的含有4个元素的信号量数组。
注意信号量数组序号是从0才是编址。
`semop(semid, struct sembuf semoparray[], size_t nops );函数中参数semid是一个通过semget函数返回的一个信号量标识符,参数nops标明了参数semoparray所指向数组中的元素个数。
参数semoparray 是一个struct sembuf结构类型的数组指针,结构sembuf来说明所要执行的操作,其定义如下:struct sembuf{unsigned short sem_num; //信号量集中的某一个信号量short sem_op; // sem_op指明所要执行的操作(1表示V操作,-1表示P操作)short sem_flg;}例:Int P(int semid){struct sembuf p;P.sem_num=1;/对第二个信号量; P.sem_op=-1;//p操作;P.sem_flag=SEM_UNDO;semop(semid,&p,1);} Int V(int semid){struct sembuf p;P.sem_num=2;//对第三个信号量; P.sem_op=1;//V操作;P.sem_flag=SEM_UNDO;semop(semid,&p,1);}对信号量进行控制semctl(int semid,int num,int cmd,union arg);系统调用semctl()的semid参数是关键字值。
第二个参数是信号量数目。
参数cmd中可以使用的命令中SETVAL设置信号量集中的一个单独的信号量的值。
返回值:如果成功,则为一个正数。
如果失败,则为-1 union semun {int val;struct semid_ds *buf;unsigned short *array;} sem;sem.val=0;//设置初值为0;semctl(sem_id,0,SETVAL,sem);//对第一个信号量设置初值为0;综上所得涉及到我们需要了全部调用函数,只要将这些函数合理的组合在一起,就得到了我们想要的实验效果了。
实验调试过程:创建共享内存和信号量以及初始状态A发送信息到共享内存C,相当于A给B发送邮件B从共享内存C中读取信息,相当于接受了邮件并查看了同理可得实验扩展:由实验的PV控制可知,当进程A的发送信息被挂起时,下面的进程B 收信息也被挂起时。
不符合常理,若调用了fork()函数,进程A又分为父进程和子进程与题意不符。
故可引进线程,线程1为收信息,线程2为发信息。
调用函数:int pthread_creat(pthread_t *thread, pthread_attr_t *attr,void *(*start_routine)(void*),void *arg);//创建线程void pthread_exit(void * retval);//结束线程int pthread_join(pthread_t th,void ** thread_return) //线程挂起附:mailA代码。