30天速通Linux 第六章信号及信号处理

发布时间:2026/10/8 23:16:23
30天速通Linux 第六章信号及信号处理 学习资料https://pan.baidu.com/s/1NZpC4NyH0OHGOPPbO9J10g?pwdh9m2 提取码: h9m2一. 信号的基本概念信号是 Linux 进程之间的一种通信机制本质是软中断。read/write等系统调用都可能被信号中断。每个信号用SIGxxx整型宏表示定义在signal.hkill -l看列表man 7 signal看说明。使用信号的目的① 让进程知道发生了某事件② 执行自己代码中的信号处理程序。信号的 3 个来源用户按键CtrlC、Ctrl\进程执行出错除 0、非法访问其他进程用kill、sigqueue发送。信号的 3 种状态状态含义递送 delivery进程对信号采取动作执行处理函数或忽略未决 pending产生到递送之间阻塞 block进程指定阻塞该信号保持未决直到解除阻塞若处理方式是忽略信号永远不会递送/未决直接丢弃。二. 信号的分类分类可靠信号不可靠信号取值SIGRTMIN~SIGRTMAX小于SIGRTMIN行为来不及处理时排队不丢失来不及处理则丢弃只留一个Linux 共 64 种信号前 32 种非实时不支持排队 不可靠后 32 种实时支持排队 可靠。按来源还分同步信号进程自身操作产生如被零除异步信号进程外事件如击键。常用信号man 7 signal完整列表信号说明默认处理SIGINTCtrlC终止SIGQUITCtrl\终止 coreSIGKILL不可捕捉、不可忽略终止SIGSTOP不可捕捉、不可忽略暂停SIGSEGV内存非法访问终止 coreSIGPIPE往已关闭的管道/socket 写终止SIGCHLD子进程停止或终止忽略SIGALRMalarm/setitimer定时到期终止SIGUSR1/2用户自定义终止SIGTSTPCtrlZ挂起暂停SIGCONT让暂停的进程继续继续/忽略三. 信号的处理3.1 三种处理方式方式说明默认处理多数导致进程终止忽略signal(SIGINT, SIG_IGN)SIGKILL/SIGSTOP不能被忽略捕捉处理注册处理函数最常用SIGKILL/SIGSTOP不能被捕捉3.2signal老机制有缺陷#includesignal.hresultsignal(intsignum,void(*action)(int));actionSIG_DFL默认SIG_IGN忽略函数名。成功返回之前的处理函数指针失败返回 -1。voidsigHandler(intsignum){printf(The sign no is:%d\n,signum);signal(SIGINT,sigHandler);// ⚠ 必须重新注册否则恢复默认}intmain(){signal(SIGINT,sigHandler);signal(SIGQUIT,SIG_IGN);// 忽略 ^\ while (1) sleep(1);}⚠signal的三个问题① 处理函数执行中又来同类信号多余丢失② 又来异类信号中断当前处理③ 阻塞系统调用如read被信号打断后如何继续。→用sigaction替代。3.3sigaction推荐intsigaction(intsignum,conststructsigaction*act,structsigaction*oldact);structsigaction{void(*sa_handler)(int);// 老式处理函数void(*sa_sigaction)(int,siginfo_t*,void*);// 带附加信息可获知信号产生原因sigset_tsa_mask;// 处理期间额外阻塞的信号集intsa_flags;// 行为选项};sa_flags作用SA_RESTART被信号打断的阻塞系统调用read/write/ioctl自动重启不设则返回 -1errnoEINTRSA_SIGINFO用sa_sigaction3 参数而不是sa_handlerSA_NODEFER处理时不阻塞新信号此时sa_mask失效SA_RESETHAND处理完自动撤消注册即signal的老行为信号集操作函数intsigemptyset(sigset_t*set);// 清空intsigfillset(sigset_t*set);// 填满所有信号intsigaddset(sigset_t*set,intsignum);// 添加intsigdelset(sigset_t*set,intsignum);// 移除intsigismember(constsigset_t*set,intsignum);// 是否包含sigprocmask全程阻塞与sa_mask的区别是它对所有场合生效intsigprocmask(inthow,constsigset_t*newset,sigset_t*oldset);how含义SIG_BLOCK把newset加入原阻塞集SIG_UNBLOCK从原阻塞集移除newsetSIG_SETMASK把阻塞集设为newset示例可靠信号排队、不可靠信号丢失sem_t信号集设SIGINT(不可靠)SIGRTMIN(可靠)→sigprocmask(SIG_BLOCK)屏蔽 → sigaction 注册SA_SIGINFO→sleep(60)期间用 kill-SIGRTMINpid发多次 →sigprocmask(SIG_SETMASK,oldmask)解除阻塞 结果6个实时信号全部被处理普通 SIGINT 只处理1次四. 信号发送函数前提发送进程的用户 ID 与接收进程相同或发送者是超级用户。函数原型作用killint kill(pid_t pid, int sig);向指定进程发信号raiseint raise(int sig);向自身发信号等价kill(getpid(), sig)sigqueueint sigqueue(pid_t pid, int sig, const union sigval value);发信号并可附带数据unionsigval{intsival_int;void*sival_ptr;};sigqueue的value只有在注册时sa_flags含SA_SIGINFO才会传给处理函数。五. 可重入函数可重入函数可被多个任务并发调用而不产生数据错误。信号处理函数中必须只用可重入函数。可重入函数中不用静态变量、不用malloc/free、不用标准 I/O 库用全局变量要小心。常见可重入函数readwriteopencloseforkexitkillraisesignalsigactionwaitwaitpidsleeplseekstatduppipesocketsendrecv等完整列表见man 7 signal的 Async-signal-safe functions。六. 父子进程的信号处理子进程继承父进程的信号处理方式直到调用exec。子进程exec后父进程中设为捕捉的信号恢复为默认处理其余不变。act.sa_sigactionintsig_handler;act.sa_flagsSA_SIGINFO;sigaction(SIGINT,act,NULL);printf(The parent pid %d\n,getpid());pidfork();// if (pid 0) execvp(ls, arg); // 打开后子进程 SIGINT 变回默认终止while(1);七. 信号处理的应用7.1 被中断的系统调用慢速设备终端、文件、网络、磁盘的系统调用会被信号中断用sigaction且设SA_RESTART时自动重启否则返回 -1 EINTR。7.2 用SIGCHLD防止僵尸进程子进程退出会向父进程发SIGCHLD默认被忽略在处理函数里wait/waitpid即可回收。voidsigchld_handler(intsig){intstatus;waitpid(-1,status,WNOHANG);if(WIFEXITED(status))printf(child process exit normally\n);elseif(WIFSTOPPED(status))printf(child process is stopped\n);}intmain(){pid_tpid;signal(SIGCHLD,sigchld_handler);pidfork();if(pid0)abort();// 子进程异常退出elseif(pid0){sleep(2);printf(parent process\n);}elseexit(0);}八. 系统定时信号8.1 睡眠函数unsignedintsleep(unsignedintseconds);// 秒voidusleep(unsignedlongusec);// 微秒unsignedintalarm(unsignedintseconds);// seconds 秒后产生 SIGALRMintpause(void);// 挂起直到收到一个信号才返回用alarmpause实现sleepvoidalarm_handler(inta){printf(sleep is over);}intmysleep(intseconds){signal(SIGALRM,alarm_handler);alarm(seconds);pause();}⚠sleep内部就是用alarm实现的不要和alarm混用。8.2 三个计时器计时器计算内容信号ITIMER_REAL真实程序运行的实际时间SIGALRMITIMER_VIRTUAL虚拟用户态消耗的时间SIGVTALRMITIMER_PROF实用用户态 内核态SIGPROF例用户态 10s 内核态 8s 睡眠 7s → 真实 25s、虚拟 10s、实用 18s。intgetitimer(intwhich,structitimerval*value);intsetitimer(intwhich,conststructitimerval*value,structitimerval*ovalue);structitimerval{structtimevalit_interval;// 重复间隔structtimevalit_value;// 初始倒计时};structtimeval{longtv_sec;longtv_usec;};// 秒 / 微秒signal(SIGALRM,alarmsign_handler);structitimervaltval;timeChange(1,tval.it_value);// 初始 1 毫秒timeChange(1000,tval.it_interval);// 每 1000 毫秒触发一次setitimer(ITIMER_REAL,tval,NULL);while(getchar()!#);// 输入 # 退出

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询