2026/5/21 22:43:12
网站建设
项目流程
上海市政建设有限公司网站,图文广告培训班多少钱,wordpress图片介绍,唐河微网站开发文章目录前言1. 阻塞信号集#xff08;Signal Mask#xff09;2. 未决信号集#xff08;Pending Signal Set#xff09;3. 两者关系与信号递达流程4. 相关系统调用简要说明5. 示例代码片段#xff08;查看 pending 与 mask#xff09;6.示例代码详解6.1 print_sigset函数…文章目录前言1. 阻塞信号集Signal Mask2. 未决信号集Pending Signal Set3. 两者关系与信号递达流程4. 相关系统调用简要说明5. 示例代码片段查看 pending 与 mask6.示例代码详解6.1 print_sigset函数6.2 main函数6.2.1 信号集初始化与阻塞6.2.2 等待用户发送信号6.2.3 查看挂起信号6.2.4 解除信号阻塞6.3 执行流程6.4 关键知识点6.5 程序运行结果分析6.6 信号处理机制详解前言在 Linux 系统中信号signal是进程间通信IPC的一种机制用于通知进程发生了某种事件。为了更精细地控制信号的处理行为内核为每个进程维护了两个关键的信号集合阻塞信号集Blocked Signal Set / Signal Mask未决信号集Pending Signal Set这两个集合都以位掩码bitmask的形式表示通常称为 sigset_t 类型。1. 阻塞信号集Signal Mask定义当前被阻塞、暂不递达的信号集合。作用即使某个信号已经发送给进程只要它在阻塞集中就不会被立即处理即不会触发信号处理函数或默认动作而是被挂起pending。修改方式通过 sigprocmask() 系统调用修改当前进程的信号掩码。特点是可编程控制的对实时信号如 SIGRTMIN~SIGRTMAX和标准信号均有效子进程会继承父进程的信号掩码在 fork 时。2. 未决信号集Pending Signal Set定义已经发送给进程、但尚未被递达因为被阻塞或正在处理的信号集合。作用记录哪些信号“在路上”等待解除阻塞后处理。查看方式可通过 sigpending() 系统调用获取当前进程的 pending 信号集。特点内核自动维护用户无法直接修改对于标准信号如 SIGINT、SIGTERM多次发送只保留一个不可排队对于实时信号POSIX Realtime Signals可以排队多个实例可 pending。3. 两者关系与信号递达流程当一个信号被发送给进程时内核执行如下逻辑检查该信号是否在 阻塞信号集mask 中如果 不在 → 立即递达调用 handler 或执行默认动作如果 在 → 将该信号加入 未决信号集pending暂不处理。当进程后续通过 sigprocmask() 解除对该信号的阻塞 时内核检查 pending 集合若该信号处于 pending 状态则立即递达。注意信号的“递达”发生在进程从内核态返回用户态时例如系统调用返回、中断返回等这是信号处理的“时机点”。4. 相关系统调用简要说明sigsuspend 常用于“等待特定信号”的场景它能避免竞态条件race condition先解除阻塞再 sleep 可能错过信号而 sigsuspend 是原子操作。5. 示例代码片段查看 pending 与 mask#includesignal.h#includestdio.h#includeunistd.hvoidprint_sigset(constsigset_t*set){for(inti1;iNSIG;i){if(sigismember(set,i))printf( %d,i);}printf(\n);}intmain(){sigset_tmask,pending;// 阻塞 SIGINT (CtrlC)sigemptyset(mask);sigaddset(mask,SIGINT);sigprocmask(SIG_BLOCK,mask,NULL);printf(Blocked SIGINT. Now send SIGINT (e.g., press CtrlC).\n);sleep(3);// 此时 SIGINT 被阻塞应进入 pendingsigpending(pending);printf(Pending signals:);print_sigset(pending);printf(Unblocking SIGINT...\n);sigprocmask(SIG_UNBLOCK,mask,NULL);// 此时会立即处理 pending 的 SIGINTreturn0;}6.示例代码详解运行此程序在 sleep 期间按 CtrlC会看到 SIGINT 被 pending解除阻塞后进程退出。这是一个用于演示Linux信号处理机制的C程序主要功能是阻塞、查看和解除阻塞SIGINT信号通常由CtrlC触发。6.1 print_sigset函数voidprint_sigset(constsigset_t*set){for(inti1;iNSIG;i){if(sigismember(set,i))printf( %d,i);}printf(\n);}功能打印信号集中的所有信号编号参数set - 指向信号集的指针实现遍历从1到NSIG系统支持的最大信号数的所有信号使用sigismember()函数检查每个信号是否在信号集中如果存在则打印该信号编号6.2 main函数6.2.1 信号集初始化与阻塞sigset_tmask,pending;// 阻塞 SIGINT (CtrlC)sigemptyset(mask);sigaddset(mask,SIGINT);sigprocmask(SIG_BLOCK,mask,NULL);sigset_t: 定义信号集类型的变量sigemptyset(): 初始化信号集为空sigaddset(): 将SIGINT信号添加到信号集中sigprocmask(SIG_BLOCK, mask, NULL): 阻塞mask中包含的所有信号这里是SIGINT6.2.2 等待用户发送信号printf(Blocked SIGINT. Now send SIGINT (e.g., press CtrlC).\n);sleep(3);// 此时 SIGINT 被阻塞应进入 pending提示用户发送SIGINT信号sleep(3): 程序休眠3秒期间如果用户按下CtrlCSIGINT信号会被阻塞并进入挂起状态6.2.3 查看挂起信号sigpending(pending);printf(Pending signals:);print_sigset(pending);sigpending(pending): 获取当前挂起的所有信号并存储到pending信号集中调用print_sigset()打印所有挂起的信号6.2.4 解除信号阻塞printf(Unblocking SIGINT...\n);sigprocmask(SIG_UNBLOCK,mask,NULL);// 此时会立即处理 pending 的 SIGINTsigprocmask(SIG_UNBLOCK, mask, NULL): 解除mask中包含的所有信号的阻塞当SIGINT信号解除阻塞后系统会立即处理之前挂起的SIGINT信号导致程序终止6.3 执行流程程序开始执行初始化信号集阻塞SIGINT信号提示用户发送SIGINT信号并休眠3秒如果用户在3秒内按下CtrlCSIGINT信号被阻塞并进入挂起状态程序醒来后检查并打印所有挂起的信号解除SIGINT信号的阻塞系统立即处理挂起的SIGINT信号程序终止6.4 关键知识点信号集(sigset_t)用于表示一组信号的数据结构sigprocmask()修改进程的信号屏蔽字控制哪些信号可以递送到进程sigpending()获取当前挂起的所有信号SIG_BLOCK向信号屏蔽字添加信号SIG_UNBLOCK从信号屏蔽字移除信号挂起信号(pending signals)已发送但被阻塞的信号这个程序很好地演示了Linux信号处理中的阻塞和挂起机制帮助理解信号如何在进程中被处理。6.5 程序运行结果分析第一次运行xxx:~/Cprogram$./sigtest Blocked SIGINT.Now sendSIGINT(e.g.,press CtrlC).^CPending signals:2Unblocking SIGINT...关键观察点程序启动后成功阻塞了SIGINT信号在3秒等待期间按下了CtrlC显示为^C程序检测到并输出了挂起的信号Pending signals: 2其中2是SIGINT信号的编号解除SIGINT阻塞后系统立即处理了挂起的SIGINT信号导致程序终止第二次运行xxx:~/Cprogram$./sigtest Blocked SIGINT.Now sendSIGINT(e.g.,press CtrlC).Pending signals:Unblocking SIGINT...关键观察点程序同样成功阻塞了SIGINT信号但这次在3秒等待期间没有按下CtrlC因此程序检测到的挂起信号列表为空Pending signals:后没有任何信号编号解除SIGINT阻塞后没有需要处理的挂起信号程序正常执行完毕6.6 信号处理机制详解信号编号SIGINT信号的编号是2这是由系统定义的标准信号编号。可以通过kill -l命令查看所有信号的编号。信号状态转换信号发送当按下CtrlC时终端会向当前前台进程组发送SIGINT信号信号阻塞由于程序使用sigprocmask(SIG_BLOCK, mask, NULL)阻塞了SIGINT信号该信号无法立即递送到进程信号挂起被阻塞的信号会进入挂起状态保存在进程的挂起信号集合中检查挂起通过sigpending()函数可以查询当前挂起的信号集合解除阻塞当使用sigprocmask(SIG_UNBLOCK, mask, NULL)解除SIGINT的阻塞后挂起的SIGINT信号会立即递送到进程信号处理SIGINT的默认处理动作是终止进程所以程序会立即终止程序行为差异的原因两次运行的差异完全是由是否在等待期间发送SIGINT信号导致的第一次运行发送了SIGINT → 信号挂起 → 解除阻塞后处理信号 → 程序终止第二次运行未发送SIGINT → 无挂起信号 → 解除阻塞后正常退出代码与运行结果的对应关系// 阻塞SIGINT信号sigprocmask(SIG_BLOCK,mask,NULL);printf(Blocked SIGINT. Now send SIGINT (e.g., press CtrlC).\n);sleep(3);// 这里是接收CtrlC的窗口// 检查挂起信号sigpending(pending);printf(Pending signals:);print_sigset(pending);// 这里输出是否有挂起的SIGINT(2)// 解除阻塞sigprocmask(SIG_UNBLOCK,mask,NULL);// 此时会立即处理挂起的SIGINT实际应用场景信号阻塞机制在实际编程中有很多应用例如原子操作保护在执行关键的原子操作时暂时阻塞某些信号避免操作被中断信号处理时序控制控制信号处理的时机确保在合适的时候处理信号信号批量处理先累积多个相同信号然后在合适的时候一次性处理这个程序很好地演示了Linux信号机制的基本概念包括信号阻塞、挂起和处理的整个流程。