用户空间、内核空间
Linux分为内核进程和用户进程:
1、内核进程共享一块内存空间,称为内核空间。
2、内核进程不能访问用户空间。
3、用户进程有自独立的地址空间,彼此隔离。
4、用户进程通过系统调用,从用户态陷入内核态,可以访问到内核空间。
进程通信的手段
1、共享内存
获取一块内存区域,两个用户进程都能够访问,便可实现进程间通信。
2、系统调用
借用内核态可以访问内核空间的特性,通过内核空间进行数据传输:
用户进程A通过系统调用,进入内核态,向内核空间写入数据;
用户进程B通过系统调用,进入内核态,从内核空间读取数据。
进程通信的本质:找到这样一块区域(如内存、磁盘、其他设备等),两个进程都能访问到,再通过这块区域进行数据交互。
Linux中的进程通信
linux中主要的进程通信包括以下几种:
通信方式 | 性能/拷贝 | 安全性 | 稳定性 | 用途 |
---|---|---|---|---|
信号(signal) | - | - | - | 事件通知,不适用于信息交换 |
信号量(Semaphore) | - | - | - | 计数器,常被用作锁机制 |
管道(pipe) | 低/2 | - | 1对1 | - |
消息队列(Message queues) | 低/2 | - | - | - |
套接字(Socket) | 低/2 | 高 | C/S架构 | - |
共享内存(Share Memory) | 高/0 | 考虑并发 | 用户维护 | - |
Binder | 中/1 | 高:进程UID标识,鉴别身份 | C/S架构 | - |
管道
管道是利用内核空间进行进程通信的,当进程创建一个管道之后,会返回两个文件描述符Fd[0]、Fd[1];Fd[0]用来读数据,Fd[1]用来写数据。
此时,如果想通过父进程向子进程通信,可以关闭父进程的Fd[0]和子进程的Fd[1];反之亦然。
管道的两次拷贝分别发生在Fd[1]写(将数据从用户空间拷贝到内核空间)、Fd[0]读(将数据从内核空间拷贝到用户空间)。管道通信需要满足几个条件:
1、互斥:读写操作必须互斥进行
2、同步:读写进程等待与唤醒
3、对方存在:只有判断对方存在时才能通信
消息队列
消息队列在内核空间维护了一个msgque链表。
通过wait-signal实现send原语
Procedure Send(rec, a); { rec为接收进程, a为发送区}
Begin
Getbuf(a.size, i); {从自由区中申请空缓冲区i}
i.sender:=a.sender; {把消息从a处copy到缓冲区i}
i.size:=a.size;
i.text:=a.text;
i.next:=0;
GetID(PCB set, rec.j); {获接收进程内部标识符j}
wait(j.mutex);
insert(j.mq , i); {把缓冲区i挂到进程rec消息链尾}
signal(j.mutex);
signal(j.sm);
END