鸿蒙内核源码分析(进程通讯篇) | 九大通讯方式一网打尽 | 中文注解HarmonyOS源码 | v28.01

原创
02/05 17:15
阅读数 2.4K

鸿蒙内核源码中文注解 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆, 四大源码仓每日同步更新< Gitee | Github | CSDN | Coding >

鸿蒙内核源码分析博客 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点每日同步更新< OSCHINA | CSDN | WeHarmony >


在这里插入图片描述

本篇开始介绍进程通讯(IPC)

读本篇之前建议先读鸿蒙内核源码分析(总目录)其他篇幅.

进程间为何要通讯 ?

鸿蒙内核默认支持 64个进程 和 128个任务. 内核设计尽量不去打扰它们,让各人过好各自的日子, 但大家毕竟在一口锅里吃饭, 不可能不与外界联系, 联系就得有方法,有规矩.

举两个应用场景说明下通讯的必要性:

一.被动式 广为熟知的shell命令 kill 9 13 ,是通过 shell任务给 13号进程发送一个干掉它的信号.

#define SIGKILL   9		//常用的命令 kill 9 13 

这是被动式通讯的场景,至于为什么要干掉你,原因可能很多啊,很可能是检测到13占用内存太多了,也可能13太低调长期不活跃,启动新进程发现没位置了,得收了你.反正系统必须得有对付你的抓手.

二.主动式的 ,比如要访问某些公共资源(全局变量,消息队列),而资源有限或具有排他性,别人正在使用导致你不能用, 所以需统一管理,要用就必须要先申请,按规矩办事,毕竟和谐社会没规矩不成方圆.

总之大概有以下几种需求需要通讯:

(1).数据传输: 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间

(2).共享数据: 多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。

(3).通知事件: 一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。

(4).资源共享: 多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。

(5).进程控制: 有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。

内核目录和系列篇更新

内核有个专门的IPC目录,详见如下. 可直接点击查看注解源码.

在这里插入图片描述

进程间通讯方式

查看源码注解点击一下 .c 文件

1.管道pipe(fs_syscall.c)

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。 调用pipe系统函数即可创建一个管道。有如下特质:

  1. 其本质是一个伪文件(实为内核缓冲区)

  2. 由两个文件描述符引用,一个表示读端,一个表示写端。

  3. 规定数据从管道的写端流入管道,从读端流出。

管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。 管道的局限性:

① 数据自己读不能自己写。

② 数据一旦被读走,便不在管道中存在,不可反复读取。

③ 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。

④ 只能在有公共祖先的进程间使用管道。

常见的通信方式有,单工通信、半双工通信、全双工通信。

鸿蒙的管道实现很简单, 详细看SysPipe函数.

2.信号(los_signal.c)

信号是用于进程间互相通信或者操作的一种机制,信号可以在任何时候发给某一进程,而无需知道该进程的状态。 如果该进程当前并未处于执行状态,则该信号就由内核保存起来,直到该进程被调度执行并传递给它为止。 如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。

软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。在软件层次上是对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是进程间通信机制中唯一的异步通信机制,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。

进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。信号机制除了基本通知功能外,还可以传递附加信息。

#define SIGHUP    1	//终端挂起或者控制进程终止
#define SIGINT    2	//键盘中断(如break键被按下)
#define SIGQUIT   3	//键盘的退出键被按下
#define SIGILL    4	//非法指令
#define SIGTRAP   5	//跟踪陷阱(trace trap),启动进程,跟踪代码的执行
#define SIGABRT   6	//由abort(3)发出的退出指令
#define SIGIOT    SIGABRT 
#define SIGBUS    7	//总线错误 
#define SIGFPE    8	//浮点异常
#define SIGKILL   9		//常用的命令 kill 9 13 
#define SIGUSR1   10	//用户自定义信号1 
#define SIGSEGV   11	//无效的内存引用, 段违例(segmentation     violation),进程试图去访问其虚地址空间以外的位置 
#define SIGUSR2   12	//用户自定义信号2
#define SIGPIPE   13	//向某个非读管道中写入数据 
#define SIGALRM   14	//由alarm(2)发出的信号,默认行为为进程终止
#define SIGTERM   15	//软件终止(software  termination)
#define SIGSTKFLT 16
#define SIGCHLD   17	//子进程结束信号
#define SIGCONT   18	//进程继续(曾被停止的进程)
#define SIGSTOP   19	//终止进程
#define SIGTSTP   20	//控制终端(tty)上 按下停止键

3.消息队列(los_queue.c)

基本概念

队列又称消息队列,是一种常用于任务间通信的数据结构。队列接收来自任务或中断的 不固定长度消息,并根据不同的接口确定传递的消息是否存放在队列空间中。

任务能够从队列里面读取消息,当队列中的消息为空时,挂起读取任务;当队列中有新消息时, 挂起的读取任务被唤醒并处理新消息。任务也能够往队列里写入消息,当队列已经写满消息时, 挂起写入任务;当队列中有空闲消息节点时,挂起的写入任务被唤醒并写入消息。如果将 读队列和写队列的超时时间设置为0,则不会挂起任务,接口会直接返回,这就是非阻塞模式。

消息队列提供了异步处理机制,允许将一个消息放入队列,但不立即处理。同时队列还有缓冲消息的作用。

队列特性

消息以先进先出的方式排队,支持异步读写。 读队列和写队列都支持超时机制。 每读取一条消息,就会将该消息节点设置为空闲。 发送消息类型由通信双方约定,可以允许不同长度(不超过队列的消息节点大小)的消息。 一个任务能够从任意一个消息队列接收和发送消息。 多个任务能够从同一个消息队列接收和发送消息。 创建队列时所需的队列空间,默认支持接口内系统自行动态申请内存的方式,同时也支持将用户分配的队列空间作为接口入参传入的方式。

4.共享内存(shm.c)

共享内存是进程间通信中最简单的方式之一。共享内存允许两个或更多进程访问同一块内存 不同进程返回了指向同一个物理内存区域的指针。当一个进程改变了这块地址中的内容的时候, 其它进程都会察觉到这个更改。

(共享内存篇)| 正在更新中...

5.信号量(los_sem.c)

基本概念

信号量(Semaphore)是一种实现任务间通信的机制,可以实现任务间同步或共享资源的互斥访问。 一个信号量的数据结构中,通常有一个计数值,用于对有效资源数的计数,表示剩下的可被使用的共享资源数,其值的含义分两种情况: 0,表示该信号量当前不可获取,因此可能存在正在等待该信号量的任务。 正值,表示该信号量当前可被获取。

以同步为目的的信号量和以互斥为目的的信号量在使用上有如下不同: 用作互斥时,初始信号量计数值不为0,表示可用的共享资源个数。在需要使用共享资源前,先获取信号量, 然后使用一个共享资源,使用完毕后释放信号量。这样在共享资源被取完,即信号量计数减至0时,其他 需要获取信号量的任务将被阻塞,从而保证了共享资源的互斥访问。另外,当共享资源数为1时, 建议使用二值信号量,一种类似于互斥锁的机制。

用作同步时,初始信号量计数值为0。任务1获取信号量而阻塞,直到任务2或者某中断释放信号量, 任务1才得以进入Ready或Running态,从而达到了任务间的同步。

使用场景

在多任务系统中,信号量是一种非常灵活的同步方式,可以运用在多种场合中,实现锁、同步、资源计数等功能, 也能方便的用于任务与任务,中断与任务的同步中。信号量常用于协助一组相互竞争的任务访问共享资源。

(信号量篇)|正在更新中...

6.互斥锁 (los_mux.c) :

基本概念

互斥锁又称互斥型信号量,是一种特殊的二值性信号量,用于实现对临界资源的独占式处理。 另外,互斥锁可以解决信号量存在的优先级翻转问题。 任意时刻互斥锁只有两种状态,开锁或闭锁。当任务持有时,这个任务获得该互斥锁的所有权, 互斥锁处于闭锁状态。当该任务释放锁后,任务失去该互斥锁的所有权,互斥锁处于开锁状态。 当一个任务持有互斥锁时,其他任务不能再对该互斥锁进行开锁或持有。

详见: (互斥锁篇) | 为何任务会因拥有锁而被迫改变优先级 ?

7.快锁 (los_futex.c)

futex 是Fast Userspace muTexes的缩写(快速用户空间互斥体),是一种用户态和内核态混合的同步机制。首先,同步的进程间通过mmap共享一段内存,futex变量就位于这段共享的内存中且操作是原子的,当进程尝试进入互斥区或者退出互斥区的时候,先去查看共享内存中的futex变量,如果没有竞争发生,则只修改futex,而不用再执行系统调用了。当通过访问futex变量告诉进程有竞争发生,则还是得执行系统调用去完成相应的处理(wait 或者 wake up)。

8.事件 (los_event.c)

基本概念 事件(Event)是一种任务间通信的机制,可用于任务间的同步。

多任务环境下,任务之间往往需要同步操作,一个等待即是一个同步。事件可以提供一对多、多对多的同步操作。 一对多同步模型:一个任务等待多个事件的触发。可以是任意一个事件发生时唤醒任务处理事件,也可以是几个事件都发生后才唤醒任务处理事件。 多对多同步模型:多个任务等待多个事件的触发。

事件特点

任务通过创建事件控制块来触发事件或等待事件。 事件间相互独立,内部实现为一个32位无符号整型,每一位标识一种事件类型。第25位不可用,因此最多可支持31种事件类型。 事件仅用于任务间的同步,不提供数据传输功能。 多次向事件控制块写入同一事件类型,在被清零前等效于只写入一次。 多个任务可以对同一事件进行读写操作。 支持事件读写超时机制。

事件可应用于多种任务同步场景,在某些同步场景下可替代信号量。

使用场景

队列用于任务间通信,可以实现消息的异步处理。同时消息的发送方和接收方不需要彼此联系,两者间是解耦的。

(事件驱动篇)|正在更新中...

9.文件消息队列 (hm_liteipc.c)

基于文件实现的消息队列,特点是队列中消息数量多(256个),传递消息内容大(可达到1K)

#define IPC_MSG_DATA_SZ_MAX 1024	//最大的消息内容 1K ,posix最大消息内容 64个字节
#define IPC_MSG_OBJECT_NUM_MAX 256	//最大的消息数量256 ,posix最大消息数量 16个

(消息队列篇)|正在更新中...

以上为鸿蒙内核的九种进程间通讯方式,源码注解已基本完成,可前往Fork查看. 每一种通讯方式博客将详细说明,正在更新中...

喜欢就请收藏吧

各大站点搜 "鸿蒙内核源码分析" ,快速找到组织.

公众号: 鸿蒙内核源码分析


鸿蒙内核源码中文注解 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆, 四大源码仓每日同步更新< Gitee | Github | CSDN | Coding >

鸿蒙内核源码分析博客 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点每日同步更新< OSCHINA | CSDN | WeHarmony >

展开阅读全文
打赏
1
2 收藏
分享
加载中
百万汉字注解鸿蒙内核源码 https://gitee.com/weharmony/kernel_liteos_a_note
02/05 18:02
回复
举报
更多评论
打赏
1 评论
2 收藏
1
分享
返回顶部
顶部