Handler的底层原理实现

本文详细解析了Handler的源码实现,包括Handler、Message、MessageQueue和Looper的工作原理。介绍了Handler如何发送和处理消息,以及在面试中常问的关于Handler的几个问题,如Handler、Looper和MessageQueue的数量限制。同时,阐述了不同线程间如何通过Handler进行通信。

Handler

相信大家对Handler再熟悉不过了,平常使用它的频率也比较高,我们知道它是用来线程间通信的,但是handler是怎么实现通信的,可能就需要我们做进一步的了解,在面试中也是经常会问到的问题,下面我就带着大家跟一跟Handler的源码。
在跟代码之前我们先对Handler原理做个大致打介绍:

Handler:用来发送消息,处理消息
Message:消息实体对象,handler通过sendMsg将实体放到消息队列里面
MessageQueue:存放消息的队列
Looper:消息轮询器,轮询消息队列的消息然后取出,交给handler处理

Handler源码

进入Handler实现,首先看一下代码行数800行,并不多,注释都有100行,所以Handler的代码相对很少,它的主要方法都有:

这里写图片描述

那么上面打方法我们应该怎么看呢?我们在看源码的时候通常会遇到这个问题,方法那么多,应该从何处看起?不要急,我来交大家一个方法:

首先看代码有多少行,心里大致有个底,然后是构造方法,看看有哪些构造函数,然后浏览一些setter,getter,这些都是一些无关紧要打东西,大致浏览即可,接下来就主要看我们调用的方法,就能找到主线了!

Handler我们经常调用的有:obtain…,sendMsg…,post…remove…new Handler(callback),挨着看就是,首先封装消息打方法obtain…

进入源码我们看obtain都做了些什么操作:
这里写图片描述

我们可以发现在方法里

### sigaction的底层原理实现机制 `sigaction` 是 Linux 系统中用于处理信号的核心函数之一,它提供了比 `signal` 更加灵活和强大的功能。以下是关于 `sigaction` 的底层原理实现机制的详细解析。 #### 1. sigaction 函数的基本定义 `sigaction` 的函数原型如下: ```c int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); ``` - `signum`: 指定要处理的信号类型。 - `act`: 指向一个新的 `sigaction` 结构体指针,用于设置新的信号处理方式。 - `oldact`: 指向一个 `sigaction` 结构体指针,用于保存旧的信号处理方式。 如果 `act` 参数为非空,则会根据其内容更新指定信号的处理方式;如果 `oldact` 参数为非空,则会将当前信号的处理方式保存到该结构体中[^4]。 #### 2. sigaction 结构体详解 `sigaction` 的核心是 `struct sigaction` 结构体,它的定义如下: ```c struct sigaction { void (*sa_handler)(int); // 信号处理函数 sigset_t sa_mask; // 额外需要屏蔽的信号集合 int sa_flags; // 标志位,用于指定额外的行为 void (*sa_restorer)(void); // 已废弃,不推荐使用 }; ``` - `sa_handler`: 指向用户定义的信号处理函数。当进程接收到指定信号时,内核会调用此函数。 - `sa_mask`: 定义了在信号处理函数执行期间需要屏蔽的其他信号集合。这可以防止在处理某个信号时被其他信号中断。 - `sa_flags`: 提供了额外的标志位选项,用于控制信号处理行为。常见的标志包括: - `SA_RESTART`: 如果信号中断了一个系统调用,则系统调用会被自动重新发起。 - `SA_NOCLDWAIT`: 当子进程终止时,父进程不会收到 `SIGCHLD` 信号。 - `SA_SIGINFO`: 使用扩展的信号处理函数原型,允许传递更多参数。 #### 3. 内核中的实现机制 `sigaction` 的底层实现主要依赖于内核中的信号机制。以下是关键步骤的解析: ##### 3.1 信号的注册与存储 当调用 `sigaction` 时,内核会将用户提供的信号处理方式存储到进程的描述符结构体中。具体来说,每个进程的 `task_struct` 中包含一个 `sigaction` 数组,用于存储每种信号的处理方式。例如: ```c struct task_struct { ... struct k_sigaction signal[SIGRTMAX]; // 存储信号处理方式 ... }; ``` `k_sigaction` 是内核中定义的一个结构体,类似于用户空间的 `sigaction`。每当调用 `sigaction` 时,内核会更新对应信号的处理方式,并将其存储到该数组中[^1]。 ##### 3.2 信号的发送与接收 当一个信号被发送时(如通过 `kill` 或 `sigqueue`),内核会调用 `send_sig()` 函数。该函数的主要任务是: 1. 查找目标进程。 2. 将信号信息存储到目标进程的 `signal` 字段中。 3. 如果目标进程处于运行状态,则立即触发信号处理逻辑。 信号的接收发生在进程从内核态返回用户态时。内核会在上下文切换时检查当前进程是否有待处理的信号。如果有,则根据 `sigaction` 设置的处理方式执行相应的操作[^1]。 ##### 3.3 信号处理函数的执行 当信号处理函数被触发时,内核会在用户的栈上创建一个新的帧,将返回地址设置为用户定义的信号处理函数地址。这样,当进程从内核态返回用户态时,会直接跳转到用户定义的信号处理函数中执行。执行完成后,再恢复原来的执行流[^1]。 #### 4. 示例代码 以下是一个简单的 `sigaction` 使用示例: ```c #include <stdio.h> #include <signal.h> #include <unistd.h> void handler(int sig) { printf("Signal %d received\n", sig); } int main() { struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGINT, &sa, NULL) == -1) { perror("sigaction"); return 1; } while (1) { printf("Waiting for signal...\n"); sleep(1); } return 0; } ``` ####
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值