实验目的
- 熟悉 Linux 下的应用程序开发;
- 熟悉 Linux 的进程控制原语的使用;
- 掌握 Linux 操作系统的进程间通信机制管道的使用;
- 掌握 Linux 操作系统中父进程与子进程的同步。
实验原理
每个进程各自有不同的用户地址空间,进程之间要交换数据必须通过内核(内核开辟的缓冲区),内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。
-
管道是一种最基本的 IPC 机制,由 pipe 函数创建:
int pipe(int fd[2]);
返回值:成功返回 0,错误返回-1。
参数 fd 为管道描述符,同文件描述符,可以使用文件 I/O 函数(close, read, write)进行操作。
fd[0]为管道读端;fd[1]为管道写端。如不需要,可以关闭相应端的描述符。 -
管道的读写:
int close(int fd); //关闭由文件描述符 fd 指定的文件
ssize_t read(fd, void *buf, size_t count); //读取管道内容
ssize_t write(fd, void *buf, size_t count); //向管道写内容 -
创建父进程和子进程:
父进程关闭写端,子进程关闭读端:
-
父进程查询子进程的退出:
子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。
调用 wait 函数或者 waitpid 函数查询子进程退出状态,此方法父进程会被挂起。
实验内容
(1)在 Linux 系统中使用系统调用 fork()创建两个子进程;
(2)使用系统调用 pipe()建立一个管道,两个子进程分别向管道各写一句话;
(3)父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。然后分别结束两个子进程的运行。
- 要求 1:在 Linux 平台下实现。
- 要求 2:fork 创建两个子进程。子进程(fork 函数让子进程完整地拷贝了父进程的整个地址空间)都有管道的读端和写端。所以在相关进程中最好关掉不用的那一端。
- 要求 3:父进程先接收子进程 P1 发来的消息,然后再接收子进程 P2 发来的消息。
- 存在两个同步问题:
①两个子进程和父进程之间(先子写后父读)
②子进程 1 和子进程 2 之间(先 1 写,再 2 写) - 使用 waitpid 函数实现父进程等待子进程运行完毕后从管道中读取数据并打印,只有子进程将数据写入管道后,父进程才能够执行打开管道操作。
实验器材
硬件环境:个人计算机
操作系统:CentOS 7
实验步骤
(1)进程间管道通信实验步骤:
- 创建一个管道;
- 创建子进程 1,向管道中写入“Child process 1 is sending a message!”,并做好跟父进程的同步执行;
- 创建子进程 2,向管道中写入“Child process 2 is sending a message!”,并做好跟父进程的同步执行;
- 父进程从管道中读取数据,并打印输出。
(2)利用管道实现进程的通信的实现流程图
(3)利用管道实现进程的通信的实现代码
-
创建管道。
-
子进程向管道写内容,父进程读取管道内容。
用 fork 函数创建子进程 p1 和 p2,p1 进行关闭管道读端、向管道写数据、子进程结束,p2 也同样。然后在父进程中用 waitpid 函数确保子进程写完数据,进行关闭管道写端、从管道读数据、打印结果。
实验结果
//Using Pipe to Realize IPC
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
int fd[2];
if (pipe(fd) == -1) //创建管道
return -1;
pid_t p1, p2;
if ((p1 = fork()) == 0) { //子进程p1
char* msg1 = "Child process 1 is sending a message!\n";
close(fd[0]); //关闭管道读端
write(fd[1], msg1, strlen(msg1)); //向管道写数据
return 0;
}
else if (p1 > 0) { //父进程
waitpid(p1, NULL, 0);
if ((p2 = fork()) == 0) { //子进程p2
char* msg2 = "Child process 2 is sending a message!\n";
close(fd[0]); //关闭管道读端
write(fd[1], msg2, strlen(msg2)); //向管道写数据
return 0;
}
else if (p2 > 0) { //父进程
waitpid(p2, NULL, 0);
char msg[100];
close(fd[1]); //关闭管道写端
read(fd[0], msg, 100); //从管道读数据
printf("%s", msg);
return 0;
}
}
else
return -1;
}
子进程 p1 向管道中写入:Child process 1 is sending a message!
子进程 p2 向管道中写入:Child process 2 is sending a message!
子进程做好跟父进程的同步执行,最后父进程读取管道内容并输出。
操作系统基础实验: