Linux下进程间通信
进程的地址空间是相互独立的,因此进程之间交互数据必须需要专门的通信机制。
概述
Linux下的主要IPC手段:
- 管道pipe。数据只能单方面流通, 只能在父子进程间进行。
- 有名管道named pipe。半双工通信方式,可用于非父子进程通信。
- 信号量semophore 进程间或不同进程间的同步手段。
- 消息队列message queue。消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息量少,管道只能承载无格式字节流以及缓冲区大小受限的缺点。
- 信号signal
- 共享内存shared memory。 映射一段能被其他进程访问的内存。共享内存能被一个进程创建但是被多个进程访问。
- 套接字socket。 可用于不同机器间的通信。
管道
管道是一个特殊的文件,这个文件只存在与内存中。创建管道时,系统为管道分配一个页面作为数据缓冲区,进行管道通信的两个进程通过读写这个缓冲区来实现通信。
dup与dup2
在子进程调用exec函数执行另外一个程序时,可以将子进程的文件描述符重定向到标准输入,新执行的程序能够从标准输入获取数据,实际上是从父进程获取输入数据。
1 |
|
有名管道
有名管道(named pipe或FIFO)。FIFO不同与管道之处在于它提供了一个路径名与之关联,以FIFO的形式存储与文件系统中。
基本使用
创建方式
可以用shell创建或者在程序中用系统函数创建。
1 |
|
读写方式
有名管道是一个硬盘上的文件,使用前需要先open()将其打开。
有名管道是存在与硬盘上的文件,而管道是存在与内存中的特殊文件
消息队列
基本概念
消息队列是存放在内核中的一个消息链表,每个消息队列用消息队列标识符标识。与管道不同的是消息队列存放在内核中,只有在内核重启或者显式的删除一个消息队列时,该消息队列才会被真正的删除。
数据结构
消息缓冲结构
向消息队列发送消息时,必须组成合理的数据 结构。Linux系统定义了一个模板数据结构msgbuf:
1 |
|
msqid_ds内核数据结构
Linux中,每个消息队列都维护着一个结构体msqid_ds。该结构体保存着当前消息队列的状态信息。该结构体定义在linux/msg.h中,具体定义如下:
ipc_perm内核数据结构
ipc_perm保存着消息队列的一些重要信息,比如消息队列关联的键值,消息队列的用户ID、组ID。
创建与读写
创建消息队列
消息队列是随着内核的存在而存在的,每个消息队列在系统范围内对应唯一的键值。通过ftok函数获取该键值
1 |
|
读写消息队列
函数原型:
1 | int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int mapflg); |
信号量
信号量大于等于0时表示可供并发进程使用的资源实体数;小于0时代表正在等待使用临界资源的进程数目。
数据结构
1 | struct semid_ds { |
共享内存
数据结构
共享内存是分配一块能被其他进程访问的内存。每个内存块在内核中维护这一个内部结构shmid_ds(和消息队列,信号量)一样,该结构定义在头文件linux/shm.h中。
1 | struct shmid_ds { |
共享内存区的创建
shmget来创建一个共享内存区。原型如下:
1 | /* |
共享内存区的操作
在使用共享内存区之前,必须通过shmat将其附加到进程的地址空间。进程就与共享内存建立了连接。shmat调用成功后会返回一个指向共享内存区的指针,使用该指针即可访问共享内存区,如果失败返回-1.代码原型如下:
1 | /* |
当进程结束使用共享内存区,要通过函数shmdt断开与共享内存区的连接。该函数声明在sys/shm.h中代码原型如下:
1 | int shmdt(const void *shmaddr); |
Linux对共享内存区的控制是通过调用函数shmctl来完成的,该函数定义在头文件sys/shm.h中,原型代码如下:
1 | /* |