进程间通信的经典实现
共享内存
共享内存的工作流程:
- 创建共享区。进程1从内存中申请一块内存作为共享区域,并且将该区域与某个Key绑定
- 映射共享区。创建共享区之后,需要将其映射到进程1的空间中才能操作。
- 访问共享区。进程2利用第一步得到的Key,访问到共享区,之后将这块内存映射到进程2的空间中。
- 进程间通信。各进程实现了对共享内存的映射后,便可以利用该区域进行信息交换。(注意:整个内存过程都没有实现同步机制,需要进程间自己实现)
管道
- 进程A和B分立管道两端,进行数据传输通信
- 管道是单向的,如果进程既要“读”也要“写”,就需要两根管道这点很像水管的特性
- 管道同时具有“读取”(read end)端和“写入”(write end)端,比如进程A从 write end 写入,进程 B 就可以从 read end 端读取到数据
- 管道容量有限制,当pipe满了后,写操作将阻塞;反之,pipe空了之后,读操作将会阻塞
- 普通的管道是匿名的,这种匿名的管道只适合有斧子关系的进程通信,如果要实现没有任何关系的管道间的通信,就需要命名管道(Named pipe)
UNIX DOMAIN SOCKET
- 简称UDS,也可以说是IPC Socket,与普通的Socket不一样,专门针对单机进程间通信提出来的。
- 大家熟知的 Network Socket 是以 TCP/IP 协议栈作为基础的,需要分包、重组 等一系列操作,而 UDS 因为是本机内的“安全可靠操作”,实现机制上并不依赖于这些协议。
- Android 中使用最多的一种IPC就是Binder,其次就是 UDS 。
RPC(REMOTE PROCEDURE CALLS)
RPC 涉及通信双方通常运行于两台不同的机器中。
同步机制的经典实现
###信号量(SEMAPHORE)
信号量与PV原语是分不开的,也是最为广泛的互斥方法之一,主要包括以下几个元素:
- Semaphore S(信号量,用于指示共享资源的可用数量)
- Operation P (可以减小S计数)
- Operation V (可以增加S计数)
P执行:S = S -1,此时判断若 S>=0 ,说明资源此时允许访问,开始操作共享资源;否则,加入等待队列,待别人释放资源后唤醒。
V执行:S=S+1,如果此时S>0,说明当前没有希望访问资源的等待者;否则,唤醒等待队列中的相关对象。
其中,PV源于都属于原子操作,意味着他们执行过程是不允许被中断的。
互斥体(MUTEX)
Mutex 是 Mutual Exclusion 的缩写,释义为 互斥体。如果资源允许多个对象同时访问,成为 Counting Semaphores;而如果只允许取值0或1(lock/unlocked)的Semaphore,则叫做 Binary Semaphore。Binary Semaphore 与Mutex有相同性质,Mutex通常是对某一排他资源的共享控制——要么这个资源被占用(locked),要么是可以访问的(unlocked)。
管程(MONITOR)
针对信号量机制的程序易读性较差,并且信号量管理分散在各个参与对象中,很难维护等缺点,管程被提出来了。管程是可以被多个进程/线程安全访问的对象或者模块,管程中的方法在同一时刻只允许一个范文这使用它们(方法受 mutual exclusion 保护的)。
操作系统内存基础
操作系统中任何操作都与内存息息相关,内存管理的底层原理主要注意几个核心:
- 虚拟内存
内存总是“不够大”的,随着应用的增加,总会填满,虚拟内存为运行更多的程序提供了可能,其基本思想是:1.将硬盘上一部分空间作为内存的扩展;2.出现资源不足时,按照一定算法挑出优先级较低的数据块移动到第1步划出的空间;3.需要用到硬盘中的数据块时,系统将产生“缺页”,之后把硬盘中的数据交换回内存中。
- 内存分配与回收
分配、native层回收,java层回收
- 内存保护
内存分页或者分段式管理。进程的逻辑地址不是直接对应物理地址的,因此没办法访问它范围外的内存空间。
顺带一提,mmap函数(Memory Map)正如其名,可以将某个设备或者文件映射到应用进程的内存空间中,这样访问这块内存就相当于对设备/文件进行读写;可见,理论上mmap可以用于进程间通信,即通过映射同一块物理内存来共享内存,这种方式因为减少了复制次数,在一定程度上提高了进程间通信效率。
Android 匿名共享内存(Ashmem)
Ashmem 全称 Anony Shared Memory,是Android 特有的内存共享机制,它可以将指定的物理内存分别映射到各个进程的地址空间,从而便捷地实现进程间的内存共享。Ashmem 是一个 misc 设备,其实现依托于 /dev/ashmem 。