进程是操作系统中一个很重要的概念。进程是操作系统分配资源的基本单位,也是CPU调度的基本单位。Linux作为多任务系统,能够同时运行几个进程。通常各个进程必须保持独立,避免彼此干扰。但是有时候,应用程序必须彼此通信。举例来说:
1.一个进程生成的数据传输到另一个进程时
2.数据由多个进程共享时
3.进程必须彼此等待时
4.需要协调资源的使用时
进程是操作系统中一个很重要的概念。进程是操作系统分配资源的基本单位,也是CPU调度的基本单位。Linux作为多任务系统,能够同时运行几个进程。通常各个进程必须保持独立,避免彼此干扰。但是有时候,应用程序必须彼此通信。举例来说:
1.一个进程生成的数据传输到另一个进程时
2.数据由多个进程共享时
3.进程必须彼此等待时
4.需要协调资源的使用时
进程间通信的几个概念:
几个进程在访问资源时彼此干扰的情况通常称之为竟态条件。
进程的执行在不应该被中断的地方被中断,从而导致进程执行不正确。将相关的代码段进行标记使之无法被调度器中断,这段代码就称为临界区。
内核可以不受限制地访问整个地址空间。在多处理器系统上(或类似地,在启用了内核抢占的单核处理器系统上),如果几个处理器同时处于核心态,则理论上它们可以同时访问同一个数据结构。内核为了避免产生竟态提供了各种锁选项,如原子操作、自旋锁、信号量、读写锁等。
Linux使用system V引入的机制,来支持用户进程的进程间通信和同步。System V的3种进程间通信(IPC)机制包括了信号量、消息队列、共享内存。
除了system V UNIX采用的IPC机制外,进程间还有其他的方法可以用来交换消息和数据。比如信号、管道和套接字等。
共享内存
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式。两个不同进程A/B共享内存的意思是,同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以看到进程B对共享内存中数据的更新。反之亦然。
共享内存方式之mmap():
mmap()函数及其相关系统调用的两种方法
(1)使用普通文件提供的内存映射:适用于任何进程之间;需要打开或创建一个文件,然后再调用mmap()。
(2)用特殊文件提供匿名内存映射:适用于具有亲缘关系的进程之间,由于父子进程特殊的亲缘关系,在父进程中先调用mmap(),然后再fork,fork之后子进程继承父进程匿名映射后的地址空间,同样也继承父进程mmap()返回的地址。
ION基本概念介绍
ION是Google的下一代内存管理器,用来支持不同的内存分配机制,如CARVOUT(PMEM),物理连续内存(kmalloc), 虚拟地址连续但物理不连续内存(vmalloc), IOMMU等。ION将内核态形形色色的内存分配纳入统一的管理接口之中,更重要的设计意图是为内存在不同用户态进程之间传递和访问提供了支持。
需要注意的问题:
1.文件描述符的传递
在不具有亲缘关系的两个进程间需要传递文件描述符时,单纯的传递一个int型的fd是没有任何实际意义的,对于进程间通信传递描述符时需要采用套接字的方法。
ion机制这样通过套接字传递文件描述,使用mmap函数进行内存映射,使得两个进程共享了同一片内存。两个不具有亲缘关系的进程也实现了匿名映射。
套接字是操作系统内核中的一个数据结构,它是网络中的节点进行相互通信的门户,是网络进程的ID。网络通信归根到底还是进程间的通信(不同计算机上的通信)。UNIX域套接字可以在同一台主机上各进程间传递文件描述符。
相关API:
#include <sys/types.h>
#include <sys/socket.h>
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ION进程间通信的用法示例:
进程B:
int size = 0x1000
ion_fd = open("/dev/ion", O_RDONLY);
fd_data.fd = get_share_fd();
ret = ioctl(ion_fd, ION_IOC_IMPORT, &fd_data);
mem = (unsigned char *)mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd_data.fd, 0);//mmap
进程A:
int ionfd = open(“/dev/ion”, O_RDONLY); //打开设备节点
alloc_data.len = 0x1000; //填充结构体
alloc_data.align = 0;
alloc_data.heap_id_mask = ION_HEAP_TYPE_DMA_MASK;
alloc_data.flags = 0;
rc = ioctl(ionfd,ION_IOC_ALLOC, &alloc_data);
fd_data.handle = alloc_data.handle;
/*映射内存*/
mem = mmap(NULL, alloc_data.len, PROT_READ|PROT_WRITE, MAP_SHARED, fd_data.fd, 0);
rc = ioctl(ionfd,ION_IOC_SHARE,&fd_data);//得到文件描述符的副本用传递给进程B
shared_fd = fd_data.fd;