嵌入式学院—华清远见旗下品牌:www.embedu.org
嵌入式学院—华清远见旗下品牌:www.embedu.org
《嵌入式 Linux 应用程序开发标准教程》——第 8 章、进程间通信
第
8
章 进程间通信
本章目标
在上一章中,读者已经学会了如何创建进程以及如何对
进程进行基本的控制,而这些都只是停留在父子进程之间的
控制,本章将要学习不同的进程间进行通信的方法,通过本
章的学习,读者将会掌握如下内容。
掌握 Linux 中管道的基本概念
掌握 Linux 中管道的创建
掌握 Linux 中管道的读写
掌握 Linux 中有名管道的创建读写方法
掌握 Linux 中消息队列的处理
掌握 Linux 共享内存的处理
嵌入式学院—华清远见旗下品牌:www.embedu.org
《嵌入式 Linux 应用程序开发标准教程》——第 8 章、进程间通信
8.1 Linux 下进程间通信概述
在上一章中,读者已经知道了进程是一个程序的一次执行。这里所说的进程一
般是指运行在用户态的进程,而由于处于用户态的不同进程之间是彼此隔离的,就
像处于不同城市的人们,它们必须通过某种方式来进行通信,例如人们现在广泛使
用的手机等方式。本章就是讲述如何建立这些不同的通话方式,就像人们有多种通
信方式一样。
Linux 下的进程通信手段基本上是从 UNIX 平台上的进程通信手段继承而来的。
而对 UNIX 发展做出重大贡献的两大主力 AT&T 的贝尔实验室及 BSD(加州大学伯
克利分校的伯克利软件发布中心)在进程间的通信方面的侧重点有所不同。前者是
对 UNIX 早期的进程间通信手段进行了系统的改进和扩充,形成了“system V IPC”,
其通信进程主要局限在单个计算机内;后者则跳过了该限制,形成了基于套接口
(socket)的进程间通信机制。而 Linux 则把两者的优势都继承了下来,如图 8.1 所
示。
UNIX 进程间通信(IPC)方式包括管道、FIFO 以及信号。
System V 进程间通信(IPC)包括 System V 消息队列、System V 信号量以
及 System V 共享内存区。
Posix 进程间通信(IPC)包括 Posix 消息队列、Posix 信号量以及 Posix 共
享内存区。
现在在 Linux 中使用较多的进程间通信方式主要有以下几种。
(1)管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程
间的通信,有名管道,除具有管道所具有的功能外,它还允许无亲缘关系进程间的
通信。
(2)信号(Signal):信号是在软件层次上对中断机制的一种模拟,它是比较
复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收
到一个中断请求效果上可以说是一样的。
(3)消息队列(Messge Queue):消息队列是消息的链接表,包括 Posix 消
息队列 SystemV 消息队列。它克服了前两种通信方式中信息量有限的缺点,具有写
权限的进程可以按照一定的规则向消息队列中添加新消息;对消息队列有读权限的
进程则可以从消息队列中读取消息。
(4)共享内存(Shared memory):可以说这是最有用的进程间通信方式。它
嵌入式学院—华清远见旗下品牌:www.embedu.org
图 8.1 进程间通信发展历程
《嵌入式 Linux 应用程序开发标准教程》——第 8 章、进程间通信
使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享
内存中数据的更新。这种通信方式需要依靠某种同步机制,如互斥锁和信号量等。
(5)信号量(Semaphore):主要作为进程之间以及同一进程的不同线程之间的
同步和互斥手段。
(6)套接字(Socket):这是一种更为一般的进程间通信机制,它可用于网络
中不同机器之间的进程间通信,应用非常广泛。
本章会详细介绍前 5 种进程通信方式,对第 6 种通信方式将会在第 10 章中单独
介绍。
8.2 管道
8.2.1 管道概述
本书在第 2 章中介绍“ps”的命令时提到过管道,当时指出了管道是 Linux 中一
种很重要的通信方式,它是把一个程序的输出直接连接到另一个程序的输入,这里
仍以第 2 章中的“ps –ef | grep ntp”为例,描述管道的通信过程,如图 8.2 所示。
图 8.2 管道的通信过程
管道是 Linux 中进程间通信的一种方式。这里所说的管道主要指无名管道,它具
有如下特点。
它只能用于具有亲缘关系的进程之间的通信(也就是父子进程或者兄弟进
程之间)。
它是一个半双工的通信模式,具有固定的读端和写端。
管道也可以看成是一种特殊的文件,对于它的读写也可以使用普通的 read()
和 write()等函数。但是它不是普通的文件,并不属于其他任何文件系统,
并且只存在于内核的内存空间中。
8.2.2 管道系统调用
1.管道创建与关闭说明
管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描
述符 fds[0]和 fds[1],其中 fds[0]固定用于读管道,而 fd[1]固定用于写管道,如图 8.3
所示,这样就构成了一个半双工的通道。
图 8.3 Linux 中管道与文件描述符的关系
嵌入式学院—华清远见旗下品牌:www.embedu.org
《嵌入式 Linux 应用程序开发标准教程》——第 8 章、进程间通信
管道关闭时只需将这两个文件描述符关闭即可,可使用普通的 close()函数逐个
关闭各个文件描述符。
注意
当一个管道共享多对文件描述符时,若将其中的一对读写文件描述符都删
除,则该管道就失效。
2.管道创建函数
创建管道可以通过调用 pipe()来实现,表 8.1 列出了 pipe()函数的语法要点。
表 8.1 pipe()函数语法要点
所需头文件
#include <unistd.h>
函数原型
int pipe(int fd[2])
函数传入值 fd[2]:管道的两个文件描述符,之后就可以直接操作这两个文件描述符
函数返回值
成功:0
出错:1
3.管道读写说明
用 pipe()函数创建的管道两端处于一个进程中,由于管道是主要用于在不同进程
间通信的,因此这在实际应用中没有太大意义。实际上,通常先是创建一个管道,
再通过 fork()函数创建一子进程,该子进程会继承父进程所创建的管道,这时,父子
进程管道的文件描述符对应关系如图 8.4 所示。
此时的关系看似非常复杂,实际上却已经给不同进程之间的读写创造了很好的
条件。父子进程分别拥有自己的读写通道,为了实现父子进程之间的读写,只需把
无关的读端或写端的文件描述符关闭即可。例如在图 8.5 中将父进程的写端 fd[1]和子
进程的读端 fd[0]关闭。此时,父子进程之间就建立起了一条“子进程写入父进程读
取”的通道。
图 8.4 父子进程管道的文件描述符对应关系 图 8.5 关闭父进程 fd[1]和子进程 fd[0]
同样,也可以关闭父进程的 fd[0]和子进程的 fd[1],这样就可以建立一条“父进程
写入子进程读取”的通道。另外,父进程还可以创建多个子进程,各个子进程都继承
了相应的 fd[0]和 fd[1],这时,只需要关闭相应端口就可以建立其各子进程之间的通
道。
想一想 为什么无名管道只能在具有亲缘关系的进程之间建立?
嵌入式学院—华清远见旗下品牌:www.embedu.org
- 1
- 2
- 3
- 4
前往页