Linux下C语言进程间无名管道通信

背景

操作系统课程习作。

环境

Ubuntu16.04 LTS
gcc version 5.4.0

关于进程通信

通信方式

Linux下进程间通信方式有以下几种:

  • 无名管道(pipe)和有名管道(FIFO)
  • 消息队列
  • 共享内存
  • 信号量
  • 信号(signal)
  • 套接字(socket)

通信用途

进程通信的用途有以下几类:

  • 数据传输:一个进程需要将它的数据发送给另一个进程。
  • 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。
  • 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
  • 资源共享的同步:多个进程之间共享同样的资源。为了做到这一点,需要内核提供锁和同步机制。
  • 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的改变状态。

从前没有进程间通信的概念,用了一下午加一晚上的时间才弄懂了无名管道方式,在此记录下来,相关知识点在下方代码中做了详细的注释。

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<unistd.h>  // 引入fork()/write()/read()
#include<sys/types.h>
#include<sys/wait.h> // 以上两个引入wait()
#include<stdio.h>
#include<stdlib.h> // 引入exit()

#define BUFFER_SIZE 50 //定义缓冲区的大小

int main()
{
int fd[2]; // 管道传输数据所用载体,fd[0]用于读管道,fd[1]用于写管道
char buf[BUFFER_SIZE]; // 存储传输的数据
char s[BUFFER_SIZE]; // 接收传输的数据
pid_t fork_id; // 存储fork()的返回值
if(pipe(fd) != 0){ // 创建半双工管道
perror("pipe");
exit(EXIT_FAILURE);
}
fork_id = fork(); //创建子进程,在子进程中返回值fork_id的值为0,在父进程中,其值为子进程的ID号
if(fork_id == 0){ // 子进程执行的程序块
printf("Locate at child process:\nsleep 2s\n");
sleep(2);
sprintf(buf, "Process communication --OS homework");
close(fd[0]); // 在子进程中先关闭读管道
write(fd[1], buf, BUFFER_SIZE); // 将数据写入管道
close(fd[1]); // 写入完毕,关闭写管道
exit(EXIT_SUCCESS); // 退出子进程,EXIR_SUCCESS是宏常量0,exit(0)表示程序正常退出
}else{ // 父进程执行的程序块
wait(0); // 等待子进程正常退出,即保证子进程的数据已都写到管道内
// printf("%s\n", buf); // 用来证明此处buf与子进程中buf相互独立,没有关联
printf("Locate at parent process:\n");
close(fd[1]); // 在父进程中先关闭写管道
read(fd[0], s, BUFFER_SIZE); // 读管道内容,s可替换为buf
close(fd[0]); // 读取完毕,关闭读管道
printf("%s\n", s); // 打印从管道中读到的数据
}
return 0;
}

注意点

  • 要先创立管道,再复制进程,即先执行pipe(),再执行fork()。次序颠倒则会在父子进程中创建出互无关联的两个管道。
  • fork()函数所创建的两个进程分占两个内存区,上例中出管道外的变量在父子进程中是互无关联。所以可以将子进程中的字符串读入buf,再将管道中的数据读到父进程的buf中输出。在此之前,父进程的buf是空的。
  • 如上一条所述,父子进程的变量互无关联,但是父子进程的管道为什么还是通用的呢?原因是子进程复制的fd[0]fd[1]是操纵管道的句柄。在终端输入命令man fork,可以看到与本例类似的示例程序,在示例程序的上方,解释了这个问题。

运行结果

运行结果

有钱的捧个钱场~