sigsuspend 与sigwait 的区别

本文详细介绍了sigsuspend与sigwait两个函数的区别。sigsuspend用于等待除指定信号集外的其他信号发生,而sigwait则专门等待指定信号集中任一信号的到来。文章还解释了两者在信号处理方式上的不同,sigsuspend会执行信号处理函数,而sigwait则直接截获信号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

sigsuspend 与sigwait 的区别
sigsuspend(const sigset_t *mask):设置阻塞信号为mask,等待其他信号(除mask之外的信号)的发生,若信号发生且对应的handler已执行,则返回-1,并设置相应的errno(已发生的信号值)。

注意:sigsuspend 总是返回-1
在程序执行到suspend之前发生的信号将不会被sigsuspend捕获
sigsuspend调用改变进程的信号掩码状态,阻塞mask 中的信号,调用返回时将掩码改为调用前的状态


sigwait(const sigset_t *mask, int *sig): 等待mask中的信号(任何一个即可)发生,若发生,设置*sig为已发生的信号,返回0。如果出错返回-1.

注意:sigwait并不等待hander执行发生的信号相当于被sigwait截获,handler 根本不会被调用执行。
sigwait调用时自动取消mask中的信号掩码状态,直到有心得信号到达,返回时恢复线程的信号屏蔽字。

sigwait的调用
等待一个信号的发生

<think>嗯,用户之前问了关于nanosleep如何不被信号中断的问题,现在接着问如何取消屏蔽信号。看来用户可能是在处理信号屏蔽的问题,可能在编写多线程或者需要精细控制信号处理的程序。 首先,用户可能已经按照之前的建议使用了sigprocmask或者pthread_sigmask来屏蔽信号,现在需要知道如何恢复原来的信号屏蔽状态。这时候,正确的做法是保存旧的信号集,并在适当的时候恢复。 用户可能没有意识到,在多线程环境中应该使用pthread_sigmask而不是sigprocmask,因为后者在多线程中的行为是未定义的。所以需要提醒用户这一点,避免潜在的错误。 另外,用户可能想知道不同的恢复方法,比如临时屏蔽和永久恢复的区别。比如,使用SIG_SETMASK来完全恢复之前的屏蔽状态,或者使用SIG_UNBLOCK来解除特定信号的屏蔽。需要解释这两种方法的适用场景,避免混淆。 用户还可能关心代码示例,特别是在实际中如何编写代码来取消屏蔽。应该提供清晰的例子,比如在阻塞信号后执行某些操作,然后恢复原状。同时,需要指出在信号处理函数中使用sigprocmask可能不安全,应该使用sigaction的sa_mask来设置。 另外,需要注意某些信号(如SIGKILL和SIGSTOP)无法被屏蔽或取消屏蔽,必须明确告知用户,避免他们尝试处理这些不可处理的信号。 最后,用户可能希望了解如何临时解除屏蔽,比如在等待某个事件时暂时允许某些信号。这时可以使用sigwait或者sigsuspend,并提供相应的示例代码。 总结来说,用户的真实需求是如何正确且安全地管理信号屏蔽状态,特别是在复杂的程序中,可能需要多次屏蔽和恢复信号。需要给出全面且详细的步骤,覆盖单线程、多线程、临时和永久恢复等情况,确保用户能够根据具体场景选择合适的解决方案。</think>在 Linux 中,**屏蔽信号(Block Signals)** 后,可以通过多种方式取消屏蔽。以下是具体方法和注意事项: --- ### **1. 核心方法:恢复原始信号屏蔽字** 通过 `sigprocmask`(单线程)或 `pthread_sigmask`(多线程)恢复之前保存的信号屏蔽字。 #### **代码示例**: ```c #include <signal.h> void unblock_signals() { // 假设 oldmask 是之前调用 sigprocmask 时保存的原始信号屏蔽字 sigset_t oldmask; // ... 其他代码中保存了 oldmask ... // 恢复原始信号屏蔽字(取消当前屏蔽) sigprocmask(SIG_SETMASK, &oldmask, NULL); } ``` --- ### **2. 分场景实现** #### **场景 1:临时屏蔽信号后恢复** ```c #include <signal.h> void temporary_block() { sigset_t mask, oldmask; sigemptyset(&mask); sigaddset(&mask, SIGINT); // 屏蔽 SIGINT(Ctrl+C) // 1. 屏蔽信号 sigprocmask(SIG_BLOCK, &mask, &oldmask); // 2. 执行需要屏蔽信号的操作(如关键代码段) // ... // 3. 恢复原始信号屏蔽字(取消屏蔽) sigprocmask(SIG_SETMASK, &oldmask, NULL); } ``` #### **场景 2:永久取消屏蔽某个信号** ```c #include <signal.h> void unblock_specific_signal() { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); // 取消对 SIGINT 的屏蔽 sigprocmask(SIG_UNBLOCK, &mask, NULL); } ``` --- ### **3. 多线程环境:使用 `pthread_sigmask`** 在多线程中,必须使用 `pthread_sigmask` 代替 `sigprocmask`: ```c #include <signal.h> #include <pthread.h> void thread_safe_unblock() { sigset_t mask, oldmask; sigemptyset(&mask); sigaddset(&mask, SIGINT); // 屏蔽信号 pthread_sigmask(SIG_BLOCK, &mask, &oldmask); // ... 执行操作 ... // 恢复原始信号屏蔽字 pthread_sigmask(SIG_SETMASK, &oldmask, NULL); } ``` --- ### **4. 动态解除屏蔽:`sigsuspend` `sigwait`** #### **(1) 临时解除屏蔽并等待信号 (`sigsuspend`)** ```c #include <signal.h> void wait_for_signal() { sigset_t mask, oldmask; sigemptyset(&mask); sigaddset(&mask, SIGINT); // 1. 屏蔽 SIGINT sigprocmask(SIG_BLOCK, &mask, &oldmask); // 2. 临时解除屏蔽并挂起,直到收到 SIGINT sigsuspend(&oldmask); // 此函数会原子地恢复 oldmask 并挂起 // 3. 恢复屏蔽(自动完成) } ``` #### **(2) 使用 `sigwait` 主动等待信号** ```c #include <signal.h> #include <stdio.h> void wait_signal_in_thread() { sigset_t mask; int sig; sigemptyset(&mask); sigaddset(&mask, SIGINT); // 屏蔽 SIGINT pthread_sigmask(SIG_BLOCK, &mask, NULL); // 等待信号(不会自动解除屏蔽) sigwait(&mask, &sig); printf("Received signal: %d\n", sig); } ``` --- ### **5. 注意事项** 1. **不可屏蔽信号**: - `SIGKILL` 和 `SIGSTOP` 无法被屏蔽或取消屏蔽(由内核强制处理)。 2. **原子性操作**: - 使用 `sigsuspend` 或 `sigwait` 时,信号屏蔽的修改和挂起操作需保持原子性,避免竞态条件。 3. **信号处理函数**: - 在信号处理函数中,默认已自动屏蔽当前信号。若需允许嵌套处理,需手动解除: ```c void handler(int signo) { // 临时解除屏蔽 sigset_t mask; sigemptyset(&mask); sigaddset(&mask, signo); sigprocmask(SIG_UNBLOCK, &mask, NULL); } ``` 4. **错误检查**: - 所有信号相关函数应检查返回值,例如: ```c if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) { perror("sigprocmask failed"); } ``` --- ### **6. 完整示例(动态屏蔽恢复)** ```c #include <signal.h> #include <stdio.h> #include <unistd.h> int main() { sigset_t mask, oldmask; // 设置屏蔽 SIGINT sigemptyset(&mask); sigaddset(&mask, SIGINT); sigprocmask(SIG_BLOCK, &mask, &oldmask); printf("SIGINT is blocked. Try Ctrl+C...\n"); sleep(5); // 在此期间 Ctrl+C 不会中断程序 // 恢复原始屏蔽字(取消屏蔽) sigprocmask(SIG_SETMASK, &oldmask, NULL); printf("SIGINT unblocked. Try Ctrl+C now.\n"); while (1) {} // 等待信号 return 0; } ``` --- 通过合理使用 `sigprocmask`、`pthread_sigmask` 和 `sigsuspend`,可以灵活控制信号的屏蔽取消屏蔽。核心原则是:**始终保存并恢复原始信号屏蔽字**,避免意外修改全局信号状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值