深入研究signal和sigaction

本文详细探讨了signal()和sigaction()在处理信号时的区别,指出signal()可能导致信号丢失的问题,而sigaction()通过信号屏蔽提供了更可靠的解决方案。通过分析Linux0.11内核源码,揭示了这两个函数的内部工作原理,帮助读者理解如何在内核中设置和管理信号处理。

信号通常使用一个无符号长整数(32位)中的比特位表示各种不同的信号。因此最多可以表示32个不同的信号。signal()和sigaction()的功能比较类似,都是更改信号原处理句柄(handler,或称为处理程序)。但signal()就是内核操作上述传统信号的方式,在某些特殊时刻可能会造成信号丢失。

之前介绍过signal()函数,signal()函数的返回值是一个无返回值且具有一个整型参数的函数指针,是默认的处理方式。并且在新句柄被调用执行过一次后,信号处理句柄又会被恢复成默认处理句柄值SIG_DFL。
在linux0.11源码中,include/signal.h文件中,默认句柄SIG_DFL和忽略处理句柄SIG_IGN的定义是:

#define SIG_DFL     ((void (*)(int))0)
#define SIG_IGN     ((void (*)(int))1)

signal()函数不可靠的原因在于当信号已经发生而进入自己设置的信号处理函数中,但在重新再一次设置自己的处理句柄之前,在这段时间内有可能又有同样的信号发生了。但是此时系统已经把处理句柄设置成默认值。因为就有可能造成信号丢失。
为了防止信号的丢失,sigaction()函数是比signal()函数更安全的选择。如果坚持要用signal(),可以在自己的信号处理函数开头再重新调用signal()函数做相同的处理。
sigaction()函数比signal()函数更可靠的原因是,在信号处理函数正在处理时,被捕捉的信号在处理期间会被自动屏蔽,并且用struct sigaction结构体中的void (*sa_handler)(int)成员修改了信号的处理方式之后,除非再改回来,否则就一直使用修改之后的处理

<think>嗯,用户这次问的是NuttX中信号(signal信号量(semaphore)的差异。虽然之前讨论过信号机制,但用户现在需要对比这两者的区别,看来是进入了更深入的进程间通信(IPC)学习阶段。 从用户引用[1]的混乱描述看,ta可能正在研究底层实现时遇到了概念混淆——这恰好说明区分signalsemaphore非常必要。用户应该是个嵌入式开发者,因为NuttX通常用在物联网设备中。 需要从三个维度展开对比: 第一维度是本质差异:信号是异步事件通知(类似中断),而信号量是同步资源计数器。举个具体例子,当线程A等待信号量时会被阻塞,但等待信号时仍能执行主程序。 第二维度是使用场景。信号更适合处理异常(比如SIGSEGV)或用户中断(Ctrl+C的SIGINT),而信号量适合保护共享资源(比如SPI总线访问)。用户如果做传感器开发,SPI总线冲突用信号量解决更合适。 第三维度要强调资源消耗。在NuttX这种RTOS里,信号量结构体只有计数器+等待队列(约12字节),而信号需要维护处理函数链表——这对STM32这类内存<64KB的设备很关键。 突然想到用户可能混淆了“信号”“信号量”的命名相似性。其实英文原文更清晰:signal是中断通知,semaphore是铁路信号灯式的资源标志。这个比喻应该能帮助ta理解。 最后要提醒信号处理的坑:NuttX的sa_flags不自动校验,这点Linux不同。如果用户从Linux转过来,特别容易在这里踩雷。</think>在NuttX中,**信号(Signal)** **信号量(Semaphore)** 是两种完全不同的进程间通信(IPC)机制,核心差异如下: --- ### 1. **本质与用途** | **机制** | **本质** | **主要用途** | |-----------|--------------------------|------------------------------------------| | **信号** | **异步事件通知** | 处理异常、中断或进程间简单通知(如`SIGKILL`终止进程) | | **信号量**| **同步资源计数器** | 控制对共享资源的访问(如临界区保护、任务同步) | --- ### 2. **工作方式对比** #### **信号(Signal)** - **异步触发**:信号由内核或进程发送,目标进程**被动响应**。 - **处理流程**: 1. 注册信号处理函数(如`sigaction()`)。 2. 信号到达时,进程暂停当前执行流,跳转到处理函数。 3. 处理完成后恢复原上下文(若未被终止)。 - **示例**: ```c void handler(int sig) { /* 处理SIGUSR1 */ } signal(SIGUSR1, handler); // 注册处理函数 kill(pid, SIGUSR1); // 向目标进程发送信号 ``` #### **信号量(Semaphore)** - **同步操作**:任务**主动请求/释放**信号量。 - **核心操作**: - `sem_init()`:初始化信号量计数器(如初始值=1)。 - `sem_wait()`:尝试获取信号量(计数器-1),若计数器=0则阻塞。 - `sem_post()`:释放信号量(计数器+1),唤醒阻塞任务。 - **示例**: ```c sem_t sem; sem_init(&sem, 0, 1); // 初始化二进制信号量(互斥锁) sem_wait(&sem); // 进入临界区(阻塞直到获取) /* 访问共享资源 */ sem_post(&sem); // 离开临界区(释放) ``` --- ### 3. **关键差异总结** | **特性** | **信号(Signal)** | **信号量(Semaphore)** | |------------------|--------------------------------|--------------------------------| | **触发方式** | 被动接收(异步) | 主动请求/释放(同步) | | **资源管理** | 无资源计数概念 | 通过计数器管理资源 | | **阻塞行为** | 处理函数执行时可能中断主流程 | `sem_wait()`可能阻塞任务 | | **数据传递** | 仅传递信号编号(无数据负载) | 不传递数据,仅控制资源访问 | | **优先级反转** | 不涉及 | 需设计优先级继承机制避免[^1] | | **适用场景** | 错误处理、强制终止、简单通知 | 资源互斥、任务同步、生产者-消费者模型 | --- ### 4. **典型场景示例** - **信号**: 硬件异常(如除零错误触发`SIGFPE`)或用户按下`Ctrl+C`(发送`SIGINT`)终止进程。 - **信号量**: 多任务竞争SPI总线时,通过二进制信号量实现互斥访问;或任务A等待任务B完成数据采集后通过计数信号量同步。 --- ### 5. **资源开销与实时性** - **信号**: 上下文切换开销较大(需保存/恢复执行现场),可能影响实时性[^2]。 - **信号量**: 轻量级阻塞(任务挂起不消耗CPU),适合资源严格的嵌入式场景。 > ⚠️ **注意**:NuttX中信号处理存在`sa_flags`未严格检查等限制,需谨慎使用[^2];而信号量需预防优先级反转问题(建议结合优先级继承协议)[^1]。 --- ### 总结 - **选择信号**:处理异步事件(如中断、错误)或简单进程控制。 - **选择信号量**:管理共享资源或需要精确同步的任务协作。 在资源受限的嵌入式系统中,信号量因确定性更高,更常用于核心逻辑的同步控制[^1][^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值