带你剖析Linux内核IPC机制(含内核源码)
Linux也支持3种IPC机制:消息队列、共享内存、信号量。在Linux内核中,IPC所有对象有一个公共的数据结构pc_perm结构,它是专门用来IPC对象权限描述,具体内核源码如下:

一、信号量
信号量解决同步、互斥问题。semaphore实际是一个整数,它的值由多个进程进行测试和设置,就每个进程所关心的测试和设置操作而言,这两个操作是不可中断,或称“原子"操作,一旦开始直到两个操作全部完成。根据测试和设置操作的结果,一个进程可能必须睡眠,直到有另一个进程改变信号量的值。
semaphore可用来实现所谓的”临界区"的互斥使用,临界区指同一时刻只有一个进程执行其中代码的代码段。Linux信号量是通过内核提供的数据结构进行实现,此数据结构在于内核空间,具体内核源码如下:

系统中每个信号量的数据结构
系统中表示信号量集合数据结构
系统中每一信号量集合的队列结构
它们三者之间关系如下:

1、系统调用:semget()
为创建一个新的信号量集合,或者存取一个已存在的集合,要使用semget()系统调用:
原型:
返回值:
参数:
key_t ftok(char* pathname,char proj)
【文章福利】小编推荐自己的Linux内核技术交流群:【891587639】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!!!前100名进群领取,额外赠送一份价值699的内核资料包(含视频教程、电子书、实战项目及代码)

二、消息队列
一个或者多个进程可向消息队列写入消息,而一个或多个进程可从消息队列中读取消息,这种进程间通信机制通常用于在客户端/服务器模型中,客户端向服务端发送请求消息,服务器读取消息并执行相应请求。内核使用msgid_ds结构描述一个消息队列。

消息队列位于内核空间的链表,链表的每个结点都是一条消息,每一条消息都有自己的消息类型,消息类型用整数来表示,并且必须大于0。
三、共享内存
共享内存允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取错做读出,从而实现了进程间的通信。
采用共享内存进行通信的一个主要好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝,对于像管道和消息队里等通信方式,则需要再内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次:一次从输入文件到共享内存区,另一次从共享内存到输出文件。

一般而言,进程之间在共享内存时,并不总是读写少量数据后就解除映射,有新的通信时在重新建立共享内存区域;而是保持共享区域,直到通信完毕为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件,因此,采用共享内存的通信方式效率非常高。

共享内存有两种实现方式:1、内存映射 2、共享内存机制
1、内存映射
内存映射 memory map机制使进程之间通过映射同一个普通文件实现共享内存,通过mmap()系统调用实现。普通文件被映射到进程地址空间后,进程可以
像访问普通内存一样对文件进行访问,不必再调用read/write等文件操作函数。
例子:创建子进程,父子进程通过匿名映射实现共享内存。
分析:主程序中先调用mmap映射内存,然后再调用fork函数创建进程。那么在调用fork函数之后,子进程继承父进程匿名映射后的地址空间,同样也继承mmap函数的返回地址,这样,父子进程就可以通过映射区域进行通信了。


2、UNIX System V共享内存机制
IPC的共享内存指的是把所有的共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。
和前面的mmap系统调用通过映射一个普通文件实现共享内存不同,UNIX system V共享内存是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信。
例子:设计两个程序,通过unix system v共享内存机制,一个程序写入共享区域,另一个程序读取共享区域。
分析:一个程序调用fotk函数产生标准的key,接着调用shmget函数,获取共享内存区域的id,调用shmat函数,映射内存,循环计算年龄,另一个程序读取共享内存。
(fotk函数在消息队列部分已经用过了,
根据pathname指定的文件(或目录)名称,以及proj参数指定的数字,ftok函数为IPC对象生成一个唯一性的键值。)


