进程间通信(IPC)介绍

1.进程间通信目的

我们知道计算机执行某个任务时可能并不是只创建一个进程去完成,可能创建了许多进程去共同完成这个任务,这些进程在在相互协调工作时,可能需要在他们之间传输数据,共享某些资源,或者通知某个事件发生,有些进程可能还需要完全控制另一个进程(如debug进程),所以就有了进程间通信,但是我们知道每个进程都有自己独立的虚拟地址空间(分为用户空间和内核空间),进程的用户空间都是独立的,一般而言都是不能访问的,唯一例外的是共享内存区,系统空间的大部分资源是所有进程共享的,各进程均可以访问的,所以内核也可以提供这样的条件,此外所有进程都可以访问外设,所以两个进程也可以通过磁盘上的普通文件进行信息交换。由此我们只要让不同的进程看到同一块资源,就可以让两个进程进行信息交换。

2.进程间通信分类

2.1 管道通信

1) 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道,自带同步机制.
2) 匿名管道只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程),命名管道则没有此限制;
3) 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
4)生命周期随进程

2.2匿名管道

创建匿名管道
头文件
#include<unistd.h>
原型
int pipe(int fd[2]);
参数:文件描述符数组,其中fd[0]表示读端fd[1]表示写端.
返回值:成功返回零,失败返回错误码。

2.3命名管道

创建一个命名管道
在linux的命令行上创建,使用下面的命令:
mkfifo filename
调用函数创建一个命名管道:
int mkfifo(const char*filename,mode_t mode);

3消息队列

消息队列提供了一种一个进程向另一个进程发送有类型的数据块的方法。消息队列和管道提供相似的服务,但消息队列要更加强大并解决了管道中所存在的一些问题。消息队列传递的消息是不连续的、有格式的信息。可以用不同的方式解释消息的类型域,如可以将消息的类型同消息的优先级联系起来,类型域也可以用来指定接收者。小消息的传送效率很高,但大消息的传送性能则较差。因为消息传送的过程中要经过从用户空间到内核空间,再从内核空间到用户空间的拷贝,所以,大消息的传送其性能较差。另外,每个消息大小也有限制,消息的总数也有限制,系统中消息队列的个数也有限制,生命周期是随内核的。

msgget函数

功能:创建或访问一个消息队列
原型
int msgget(key_t key,int msgflag);
key:某个消息队列的名字。
msgflag:由九个权限标志位,跟文件的mode一样。
返回值:成功返回一个非负整数,失败返回-1。

msgctl函数

消息队列的控制函数
原型
int msgctl(int msgid,int cmd,struct msgid_ ds*buf);
msgid:msgget的返回值。
cmd:将要采取的三个动作。
返回值:成功返回0,失败返回-1.

msgsnd函数

功能:将一条消息添加到指定消息队列中。
原型
int msgsd(int msqid,const void *msgp,size_t mssz,int flag);
msgid:由msgget函数返回的消息队列的标识码。
msgp:是一个指针,指向准备发送的消息 。
msgflag:控制当前消息队列满或者达系统上限时将要发生的事情。
返回值:成功返回0,失败返回-1。
msgrcv 函数
函数原型
ssize_t msgrcv(int msgid,void *msgp,size_t msgz,long msgtyp,int msgflg);
msgid:由msgget函数返回的消息队列的标识码。
msgp:是一个指针,指向准备接受的消息 。
msgsz:是msgp指向的消息长度,这个长度不包含消息类型的那个long int 长整型。
msgtype:它可以实现接受优先级的简单形式。msgflag:控制当前消息队列满或者达系统上限时将要发生的事情。

ipcs&ipcrm命令

ipcs显示资源
ipcrm手动删除ipc资源
ipcs -q查看内存有多少消息队列。
ipcrm -q id 删除某消息队列

4.共享内存

共享内存区是最快的IPC形式,一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,进程不再通过执行进入内核的系统调用来传递数据。
注意:共享内存没有进行同步与互斥。

共享内存示意图

进程间通信(IPC)介绍

共享内存函数
shmget函数

功能:用来创建共享内存
int shmget(key_t key,size_t size,int shmflag);
参数
key:这个共享内存段名字
size:共享内存大小
shmflg:由九个权限标志构成,用法和创建文件时用的mode模式标志一样。
返回值:成功返回一个非负整数,即该内存段的标识码,失败返回-1。

shmat函数

功能:将共享内存连接到进程地址空间
原型
void* shmat(int shmid,const void*shmaddr,int shmflg);
参数
shmid :共享内存标识
shmaddr:指定连接地址(一般都填写NULL).
shmflg:它的两个可能取值是SH_M_RND和SHM_RDONLY。
返回值:成功返回一个指针,指向共享内存第一个字节,失败返回NULL。

shmdt函数

功能:将共享内存段与当前进程脱离
原型
int shmdt(const void*shmaddr);
参数
shmaddr:由shmat所返回的指针。
返回值:成功返回0,失败返回-1.
注意:将共享内存段与当前进程脱离不等于删除共享内存段。

shmctl函数

功能:用于控制共享内存。
原型
int shmctl(int shmid,int cmd,struct shmid_ds*buf);
参数
shmid由shmget返回的共享内存的标识码。
cmd:将要采取的动作。
buf:指向一个保存着共享内存的模式状态和访问权限的数据结构。
返回值:成功返回0失败1返回-1。
cmd选项的取值
进程间通信(IPC)介绍

ipcs&ipcrm命令

ipcs -m查看内存有多少共享内存。
ipcrm -m id 删除某共享内存。

5.信号量

信号量主要用于同步与互斥机制。
进程互斥
1)由于各进程要求共享资源,而且有些资源必须互斥访问,因此各进程之间竞争使用这些资源,进程的这种关系称为进程的互斥
2)系统中的某些资源一次只允许一个进程使用,称这样的资源为临界资源或者互斥资源
3)在进程中涉及到互斥资源的程序叫临界区
进程同步
多个进程共同协作完成一个任务。
信号量与P,V原语
信号量
互斥P,V在一个进程中。
同步P,V在不同的进程中。
信号量值的含义
S大于0,S表示可用的资源数
S等于0,表示无资源可用,也无进程等待资源。
S小于0,表示没有资源可用,并且还有S个进程等待请求资源。
ipcs&ipcrm命令
ipcs -s查看内存有多少信号量。
ipcrm -s id 删除某信号量。

进程间通信总结

1)每个ipc资源的创建和控制都有一套个性化的接口。
2)ipc资源必须删除,否则不会自动删除,除非重启。
3)管道:速度慢,容量有限,只有父子进程能通讯
4)FIFO:任何进程间都能通讯,但速度慢
5)消息队列:容量受到系统限制,操作复杂。
6)信号量:不能传递复杂消息,只能用来同步和互斥。
7)共享内存区:能够很容易控制容量,速度快,不用在内核和用户空间进行数据的来回拷贝。但要保持同步和互斥,比如一个进程在写的时候,另一个进程要注意读写的问题。