Linux系统编程-信号(黑马笔记)
当一个进程跟另外一个进程发送信号后接收信号的进程有以下几种行为1.执行默认处理 2.忽略 3.捕捉后特定处理1.kill函数发送信号的函数#include sys/types.h #include signal.h int kill(pid_t pid, int sig);参数说明pid指定接收信号的进程 ID进程标识符有几种特殊情况pid 0向 PID 为pid的单个进程发送信号。pid 0向当前进程所在的进程组中所有进程发送信号。pid -1向系统中所有有权限发送的进程发送信号一般用于管理员操作。pid -1向 PID 为|pid|的进程组中所有进程发送信号。sig指定要发送的信号如SIGKILL、SIGTERM、SIGALRM等常见信号SIGKILL强制终止进程无法被捕获或忽略、SIGTERM请求终止进程可被捕获处理、SIGSTOP暂停进程等。若sig 0不发送任何信号仅用于检查目标进程是否存在返回值可判断进程是否存活。返回值成功返回0。失败返回-1并设置errno表示错误原因如目标进程不存在、无权限发送信号等。这里必须在父进程中找到对应的子进程id#include stdio.h #include stdlib.h #include sys/types.h #include signal.h #include unistd.h void sys_err(const char *str) { perror(str); exit(1); } int main() { pid_t pid; pid_t res; int i; for(i0;i5;i){ pid fork(); if(i2){ //这里必须在父进程中获取子进程的id才行 res pid; } if(pid0) { break; } // 子进程跳出循环 } if (pid 0) { sleep(5); // 让子进程先运行一会 // 向子进程发送SIGTERM信号 if (kill(res, SIGTERM) -1) { sys_err(kill error); } printf(parent process send SIGTERM to child process\n); } else if (pid 0) { while (1) { printf(child process is running, my %dth\n, i1); sleep(1); } } else { sys_err(fork error); } return 0; }2.alarm函数alarm函数是 Unix/Linux 系统中用于设置一次性定时器的系统调用作用是在指定时间秒数后向当前进程发送SIGALRM信号与之前提到的定时器信号相同。函数原型#include unistd.h unsigned int alarm(unsigned int seconds);参数与返回值参数seconds指定定时器的秒数。若seconds 0取消当前已设置的闹钟如果存在。若seconds 0设置一个新的闹钟seconds秒后发送SIGALRM信号。返回值如果之前没有设置过未到期的闹钟返回0。如果之前已设置过闹钟且尚未到期返回剩余的秒数即距离上一个闹钟到期还剩多少秒同时新的闹钟会覆盖旧的设置。核心功能alarm函数会让系统在seconds秒后自动向当前进程发送SIGALRM信号。默认情况下SIGALRM信号的处理行为是终止进程但可以通过signal函数注册自定义处理函数如之前代码中的myfunc从而实现 “定时执行某个操作” 的效果。需要注意的是alarm是一次性定时器信号触发后定时器自动失效若需周期性触发需在信号处理函数中再次调用alarm重置。#include stdio.h #include unistd.h #include signal.h #include sys/time.h int main(void) { int i; //自然时间 alarm(1); for(i 0; ; i) printf(%d\n, i); return 0; }3.setitimer函数等待的时间和定时器的时间内是不是都在运行主程序只是时间到了会触发中断运行一次处理函数然后继续执行主程序豆包答是的你的理解完全正确函数原型#include sys/time.h int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);参数说明which指定定时器类型有 3 种可选ITIMER_REAL实时时钟以系统真实时间计时到期后发送SIGALRM信号与alarm一致。ITIMER_VIRTUAL虚拟时钟仅计算进程在用户态运行的时间到期后发送SIGVTALRM信号。ITIMER_PROF统计时钟计算进程在用户态 内核态的总运行时间到期后发送SIGPROF信号。最常用的是ITIMER_REAL对应真实时间的定时new_value指向struct itimerval结构体的指针用于设置定时器的参数首次触发时间和周期结构体定义如下c运行struct itimerval { struct timeval it_interval; // 周期性触发的时间间隔0表示仅触发一次 struct timeval it_value; // 首次触发的延迟时间0表示关闭定时器 }; struct timeval { time_t tv_sec; // 秒数 suseconds_t tv_usec; // 微秒数0-999999 };old_value指向struct itimerval结构体的指针用于存储上一次定时器的设置若不需要可传NULL。返回值成功返回0。失败返回-1并设置errno表示错误原因如参数无效。#include stdio.h #include signal.h #include sys/time.h #include stdlib.h int count0; void myfunc(int signo) { printf(count %d\n,count); count0; } int main(void) { struct itimerval it, oldit; signal(SIGALRM, myfunc); //itvalue:第一次定时器到期的时间间隔 it.it_value.tv_sec 1; it.it_value.tv_usec 0; //itinterval:后续定时器到期的时间间隔 sec是秒usec是微秒两个之和是最后的时间 it.it_interval.tv_sec 2; it.it_interval.tv_usec 0; if (setitimer(ITIMER_REAL, it, oldit) -1) { perror(setitimer error); return -1; } while (1){ count; } return 0; }4.sigaction函数函数原型#include signal.h int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);参数说明signum类型为int表示需要处理的信号编号。在 Linux 系统中常见的信号有SIGINT通常由Ctrl C触发编号为 2 、SIGQUIT通常由Ctrl \触发编号为 3 、SIGTERM程序终止信号编号为 15 等。不同的信号有不同的默认行为通过sigaction函数可以改变这些默认行为。act类型为const struct sigaction *是一个指向sigaction结构体的指针用于指定信号signum的新处理方式。sigaction结构体通常包含以下几个重要成员sa_handler这是一个函数指针指向自定义的信号处理函数。当接收到指定信号时系统就会调用这个函数来处理信号。例如在前面的代码中act.sa_handler sig_catch;就是将sig_catch函数设置为对应信号的处理函数。sa_mask是一个信号集用于指定在执行信号处理函数时需要额外屏蔽的信号。也就是说在处理某个信号期间如果又收到了sa_mask中包含的信号这些信号会被暂时阻塞直到当前信号处理函数执行完毕。可以使用sigemptyset函数来清空信号集用sigaddset函数向信号集中添加信号。sa_flags是一些标志位用于指定信号处理的一些选项常见取值有0表示使用默认行为。⬇️SA_RESTART若信号中断了某些系统调用如read、write等在信号处理完成后会自动重启这些系统调用而不是让系统调用返回错误。oldact类型为struct sigaction *也是一个指向sigaction结构体的指针。如果它不为NULLsigaction函数会将信号signum原来的处理方式存储到oldact指向的结构体中。这样后续如果需要恢复信号的原来处理方式可以再次调用sigaction函数并传入保存的oldact信息。返回值sigaction函数调用成功时返回0。调用失败时返回-1并且会设置errno来指示错误原因常见的错误原因有无效的信号编号等。#include stdio.h #include stdlib.h #include signal.h #include string.h #include unistd.h // 包含 sleep 函数的声明 void sys_err(const char *str) { perror(str); exit(1); } //为了避免死循环默认情况下是自动屏蔽自己的信号的 void sig_catch(int signo) // 回调函数 { if (signo SIGINT) { sleep(10); printf(catch you!! %d\n, signo); } else if (signo SIGQUIT) printf(catch SIGQUIT!! %d\n, signo); return; } int main(int argc, char *argv[]) { struct sigaction act, oldact; act.sa_handler sig_catch; // 设置回调函数 sigemptyset(act.sa_mask); // 清空sa_mask屏蔽字只在sig_catch工作时有效 默认初始化变成不屏蔽所有 //添加屏蔽字 sigaddset(act.sa_mask,SIGQUIT); //仅仅只是执行期间 act.sa_flags 0; // 设置信号处理的方式 默认情况下为0 int ret sigaction(SIGINT, act, oldact); // 注册SIGINT信号捕捉函数 if (ret -1) sys_err(sigaction error for SIGINT); ret sigaction(SIGQUIT, act, oldact); // 注册SIGQUIT信号捕捉函数 if (ret -1) sys_err(sigaction error for SIGQUIT); while (1); return 0; }通过sigaction函数对子进程进行回调回收#include stdio.h #include stdlib.h #include unistd.h #include signal.h #include sys/types.h #include sys/wait.h // 信号处理函数用于回收子进程 void catch_child(int signo) { pid_t pid; int status; // 循环回收所有已终止的子进程防止僵尸进程 while ((pid waitpid(-1, status, WNOHANG)) 0) { if (WIFEXITED(status)) { printf(子进程 %d 正常退出退出码%d\n, pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf(子进程 %d 被信号 %d 终止\n, pid, WTERMSIG(status)); } } } int main() { pid_t pid; sigset_t set; // 阻塞 SIGCHLD 信号 sigemptyset(set); sigaddset(set, SIGCHLD); sigprocmask(SIG_BLOCK, set, NULL); int i; for (i 0; i 15; i) { if ((pid fork()) 0) { // 子进程直接退出 break; } } if (i 15) { // 父进程逻辑 struct sigaction act; act.sa_handler catch_child; // 设置信号处理函数 sigemptyset(act.sa_mask); // 清空信号屏蔽集 act.sa_flags 0; // 默认属性 // 注册 SIGCHLD 信号的处理函数 sigaction(SIGCHLD, act, NULL); // 解除对 SIGCHLD 信号的阻塞 sigprocmask(SIG_UNBLOCK, set, NULL); printf(Im parent, pid %d\n, getpid()); // 模拟父进程后续逻辑持续运行 while (1) { sleep(1); } } else { // 子进程逻辑直接打印后退出 printf(Im child pid %d\n, getpid()); exit(0); } return 0; }

相关新闻

5分钟上手:res-downloader 网络资源嗅探下载完整指南(视频号/抖音/m3u8/直播流)

5分钟上手:res-downloader 网络资源嗅探下载完整指南(视频号/抖音/m3u8/直播流)

5分钟上手:res-downloader 网络资源嗅探下载完整指南(视频号/抖音/m3u8/直播流) 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/Git…

2026/10/28 19:48:40 阅读更多 →
Tasmota WebInstaller 刷机指南:零基础 3 分钟完成固件刷写与初始配置

Tasmota WebInstaller 刷机指南:零基础 3 分钟完成固件刷写与初始配置

Tasmota WebInstaller 刷机指南:零基础 3 分钟完成固件刷写与初始配置 【免费下载链接】Tasmota Alternative firmware for ESP8266 and ESP32 based devices with easy configuration using webUI, OTA updates, automation using timers or rules, expandability …

2026/11/2 2:35:31 阅读更多 →
IDM-VTON 数据准备指南:Detectron2 内置数据集的目录结构与 DETECTRON2_DATASETS 环境变量配置

IDM-VTON 数据准备指南:Detectron2 内置数据集的目录结构与 DETECTRON2_DATASETS 环境变量配置

计算机视觉深度学习媒体生成 【免费下载链接】IDM-VTON [ECCV2024] IDM-VTON : Improving Diffusion Models for Authentic Virtual Try-on in the Wild 项目地址: https://gitcode.com/GitHub_Trending/id/IDM-VTON 点击查看 免费下载 导读 本篇技术指南聚焦于 I…

2026/10/24 22:07:59 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/3 1:09:25 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/3 10:57:27 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/3 11:35:49 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/3 2:27:21 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/3 10:47:27 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/3 10:57:33 阅读更多 →

日新闻

周新闻

月新闻