linux下进程间通信的几种主要手段简介:
- 管道(Pipe)及有名管道( mkpipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;
- 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数);
- 消息队列(Message):消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。
- 共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
- 信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
- 套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字。
1)无名管道:
2)有名管道:
不同于管道之处在于它提供一个路径名与之关联,以FIFO的文件形式存在于文件系统中。这样,即使与FIFO的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过FIFO相互通信(能够访问该路径的进程以及FIFO的创建进程之间),因此,通过FIFO不相关的进程也能交换数据。值得注意的是,FIFO严格遵循先进先出(first in first out),对管道及FIFO的读总是从开始处返回数据,对它们的写则把数据添加到末尾。它们不支持诸如lseek()等文件定位操作。
有名管道的创建:
二.信号
13) SIGPIPE
17) SIGCHLD
21) SIGTTIN
25) SIGXFSZ
29) SIGIO
35) SIGRTMIN+1
39) SIGRTMIN+5
43) SIGRTMIN+9
47) SIGRTMIN+13
51) SIGRTMAX-13
55) SIGRTMAX-9
59) SIGRTMAX-5
63) SIGRTMAX-1
gaolu@gaolu-desktop:~$
消息队列是一个消息链表,允许一个或多个进程向它写消息,另外的进程从中读取消息,具有FIFO的特性,但是可实现随即访问。在内核中,消息队列由"队列id"标识。
创建消息队列==>添加消息==>读取消息==>删除队列
<1>创建消息队列 msgget()
参数:key |
<2>向消息队列添加消息
参数:msgid
msgbuf在头文件中未实际定义,需要自己定义。 返回:成功,返回消息队列识别代码 |
<3>从消息队列读取消息
参数: msgid 返回:成功,返回消息队列识别代码 |
<4>控制消息队列
参数: msgid 返回:成功,返回消息队列识别代码 |
首先要用的函数是shmget,它获得一个共享存储标识符。
#i nclude <sys/types.h>
该函数为获取一个共享内存的标识符,其中key变量可以通过ftok()来获得
Size为需要的共享内存大小,shmflg是共享内存标志:IPC_CREAT、IPC_EXCL、;其中IPC_CREAT用于生成一个新的共享内存段,当IPC_CREAT与IPC_EXCL一起使用时,当所要创建的共享内存段已经存在时,将会返回一个EEXIST错误
该函数用于将一个共享内存段连接到地址空间中,其中shmid为共享内存段的标识符;
shmaddr:
(1) 如果shmaddr为0,则此段连接到由内核选择的第一个可用地址上。
(2) 如果shmaddr非0,并且没有指定SHM_RND,则此段连接到shmaddr所指定的地址上。
(3) 如果shmaddr非0,并且指定了SHM_RMD,则此段连接到(shmaddr-(shmaddr mod SHMLBA))
所表示的地址上。SHM_RND命令的意思是:取整。SHMLBA的意思是:低边界地址倍数,它总是2的乘方。该算式是将地址向下取最近1个SHMLBA的倍数。
除非只计划在一种硬件上运行应用程序,否则不用指定共享段所连接到的地址。所以一般应指定shmaddr为0,以便由内核选择地址。
五.信号量
(1) 测试控制该资源的信号量。
(2) 若此信号量的值为正,则允许进行使用该资源。进程将进号量减1。
(3) 若此信号量为0,则该资源目前不可用,进程进入睡眠状态,直至信号量值大于0,进程被唤醒,转入步骤(1)。
(4) 当进程不再使用一个信号量控制的资源时,信号量值加1。如果此时有进程正在睡眠等待此信号量,则唤醒此进程。
信号量函数定义如下:
#include <sys/sem.h>
int semget(key_t key, int num_sems, int sem_flags);
semget函数创建一个新的信号量或是获得一个已存在的信号量键值。
key是一个建我们可以用ftok函数来获得。key是一个整数值,不相关的进程将通过这个值去访问同一信号量。
函数semop用来改变信号量的状态,第一个参数,sem_id,是由semget函数所返回的信号量标识符。第二个参数,sem_ops,是一个指向结构数组的指针,其中的每一个结构至少包含下列成员:
struct sembuf {
}
semop的所用动作会同时作用,从而避免多个信号量的使用所引起的竞争条件。我们可以在手册页中了解关于semop处理更为详细的信息
第一个参数,sem_id,是由semget所获得的信号量标识符。sem_num参数是信号量数目。
通常的command值为:
SETVAL:用于初始化信号量为一个已知的值。所需要的值作为联合semun的val成员来传递。在信号量第一次使用之前需要设置信号量。
IPC_RMID:当信号量不再需要时用于删除一个信号量标识。