linux——信号

张开发
2026/6/10 16:36:40 15 分钟阅读
linux——信号
信号通信其实就是内核向用户空间进程发送信号只有内核才能发信号用户空间进程不能发送信号。内核可以发送多少种信号呢使用命令kill -l就可以查看我们之前终止进程用的就是第9个信号通信的框架信号的发送发送信号进程kill、raise、alarm信号的接收接收信号进程 : pause()、 sleep、 while(1)信号的处理接收信号进程 :signal1.信号的发送发送信号进程kill:所需头文件#includesignal.h #includesys/types.h 函数原型int kill(pid_t pid, int sig); 参数 函数传入值pid 正数要接收信号的进程的进程号 0信号被发送到所有和pid进程在同一个进程组的进程 ‐1信号发给所有的进程表中的进程(除了进程号最大的进程外) sig信号 函数返回值成功 0 出错 ‐1首先我们先写一个死循环进程#includestdio.h int main() { while(1); return 0; }然后我们再写kill函数#includestdio.h #includestdlib.h #include sys/types.h #include signal.h int main(int argc,char*argv[]) { int sig,pid; if(argc 3) { printf(input error\n); return -1; } sig atoi(argv[1]); pid atoi(argv[2]); printf(sig %d,pid %d,sig,pid); kill(pid,sig); return 0; }这个函数等同于终端命令kill -9 pidraise: 发信号给自己 kill(getpid(), sig)所需头文件: #includesignal.h #includesys/types.h 函数原型 int raise(int sig); 参数 函数传入值sig信号 函数返回值 成功 0 出错 ‐1#includestdio.h #include signal.h #include sys/types.h #include unistd.h #include sys/wait.h int main() { pid_t pid; pidfork(); if(pid0) { sleep(8); while(1); } if(pid 0) { printf(before sig\n); raise(SIGTSTP); printf(after sig\n); } return 0; }父进程在sleep子进程暂停因为自己给自己发送了暂停的信号8秒后父进程runing因为到了死循环子进程还是暂停#includestdio.h #include signal.h #include sys/types.h #include unistd.h #include sys/wait.h int main() { pid_t pid; pidfork(); if(pid0) { sleep(8); if(waitpid(pid,NULL,WNOHANG) 0) { kill(pid,9); } while(1); } if(pid 0) { printf(before sig\n); raise(SIGTSTP); printf(after sig\n); } return 0; }父进程还是sleeping子进程暂停了8秒后父进程进入了while(1)子进程被杀死了但是因为父进程没回收所以子进程是僵尸进程#includestdio.h #include signal.h #include sys/types.h #include unistd.h #include sys/wait.h int main() { pid_t pid; pidfork(); if(pid0) { sleep(8); if(waitpid(pid,NULL,WNOHANG) 0) { kill(pid,9); } wait(NULL); while(1); } if(pid 0) { printf(before sig\n); raise(SIGTSTP); printf(after sig\n); } return 0; }父进程sleeping子进程暂停8秒后子进程被回收了只有父进程了alarm : 发送闹钟信号的函数alarm 与 raise 函数的比较相同点让内核发送信号给当前进程不同点alarm 只会发送SIGALARM信号alarm 会让内核定时一段时间之后发送信号 raise会让内核立刻发信号所需头文件#include unistd.h 函数原型 unsigned int alarm(unsigned int seconds) 参数 seconds指定秒数 返回值 成功如果调用此alarm()前进程中已经设置了闹钟时间则返回上一个闹钟时间的剩余时间否则返回0。 出错‐1#includestdio.h #includeunistd.h #includestdlib.h int main() { int i 0; printf(before alarm\n); alarm(7); printf(after alarm\n); while(i20) { i; sleep(1); printf(process %d\n,i); } return 0; }信号名含义默认操作SIGHUP该信号在用户终端连接 (正常或非正常) 结束时发出通常是在终端的控制进程结束时通知同一会话内的各个作业与控制终端不再关联。终止SIGINT该信号在用户键入 INTR 字符 (通常是 Ctrl-C) 时发出终端驱动程序发送此信号并送到前台进程中的每一个进程。终止SIGQUIT该信号和 SIGINT 类似但由 QUIT 字符 (通常是 Ctrl-) 来控制。终止SIGILL该信号在一个进程企图执行一条非法指令时 (可执行文件本身出现错误或者试图执行数据段、堆栈溢出时) 发出。终止SIGFPE该信号在发生致命的算术运算错误时发出。这里不仅包括浮点运算错误还包括溢出及除数为 0 等其它所有的算术的错误。终止SIGKILL该信号用来立即结束程序的运行并且不能被阻塞、处理和忽略。终止SIGALRM该信号当一个定时器到时的时候发出。终止SIGSTOP该信号用于暂停一个进程且不能被阻塞、处理或忽略。暂停进程SIGTSTP该信号用于暂停交互进程用户可键入 SUSP 字符 (通常是 Ctrl-Z) 发出这个信号。暂停进程SIGCHLD子进程改变状态时父进程会收到这个信号忽略SIGABRT该信号用于结束进程终止2.信号的接收接收信号的进程要有什么条件要想使接收的进程能收到信号这个进程不能结束 :sleeppause进程状态为S函数原型 int pause(void); 函数返回值 成功0出错‐1#includestdio.h #includeunistd.h #includestdlib.h int main() { int i 0; printf(before alarm\n); pause; printf(after alarm\n); while(i20) { i; sleep(1); printf(process %d\n,i); } return 0; }进程调用 pause () → 立刻进入休眠状态不占 CPU不执行任何代码一直卡在这里死等只有收到信号比如 CtrlC、SIGALRM、kill才会继续往下走3、信号的处理收到信号的进程应该怎样处理 处理的方式1.进程的默认处理方式内核为用户进程设置的默认处理方式A忽略B终止进程C: 暂停2.自己的处理方式自己处理信号的方法告诉内核这样你的进程收到了这个信号就会采用你自己的的处理方式。所需头文件 #include signal.h 函数原型 void (*signal(int signum, void (*handler)(int)))(int); 函数传入值 signum指定信号 handler SIG_IGN忽略该信号。 SIG_DFL采用系统默认方式处理信号 自定义的信号处理函数指针 函数返回值 成功设置之前的信号处理方式 出错‐1 signal 函数有二个参数第一个参数是一个整形变量信号值第二个参数是一个函数指针是我们自己写的处理函数这个函数的返回值是一个函数指针。#includestdio.h #includeunistd.h #includestdlib.h #include signal.h void myfun(int signum) { int i 0; while(i10) { printf(process signum %d i %d\n,signum,i); sleep(1); i; } } int main() { int i 0; signal(14,myfun); alarm(7); printf(before alarm\n); printf(after alarm\n); while(i20) { i; sleep(1); printf(process %d\n,i); } return 0; }signal(14,myfun)d的意思告诉系统如果收到 14 号信号不要终止程序而是去执行 myfun 函数#includestdio.h #includeunistd.h #includestdlib.h #include signal.h void myfun(int signum) { int i 0; while(i10) { printf(process signum %d i %d\n,signum,i); sleep(1); i; } } int main() { int i 0; signal(14,myfun); alarm(7); printf(before alarm\n); printf(after alarm\n); signal(14,SIG_IGN); while(i20) { i; sleep(1); printf(process %d\n,i); } return 0; }signal(14,SIG_IGN)的意思收到14号信号直接忽略不处理也不中断#includestdio.h #includeunistd.h #includestdlib.h #include signal.h void myfun(int signum) { int i 0; while(i10) { printf(process signum %d i %d\n,signum,i); sleep(1); i; } } int main() { int i 0; signal(14,myfun); alarm(7); printf(before alarm\n); printf(after alarm\n); signal(14,SIG_IGN); signal(14,SIG_DFL); while(i20) { i; sleep(1); printf(process %d\n,i); } return 0; }这段代码总共有3个signal但是最终会执行最后一个signal(14,SIG_DFL)的意思是收到14号信号按系统默认动作执行14 号信号SIGALRM的默认动作终止进程直接杀死程序也就是说时间一到7 秒内核发 14 号信号程序收到按默认动作 → 直接退出程序4、信号父子进程间通信#includestdio.h #include sys/types.h #include unistd.h #include signal.h #includestdlib.h #include sys/wait.h void myfun(int signum) { int i 0; while(i 5) { printf(receive signum is %d,i%d\n,signum,i); sleep(1); i; } } int main() { pid_t pid; pid fork(); if(pid0) { int i 0; signal(10,myfun); while(1) { printf(process i%d\n,i); sleep(1); i; } } if(pid 0) { sleep(3); kill(getppid(),10); sleep(6); } return 0; }子进程执行3秒后发送10号信号父进程收到10号信号开始执行myfunmyfun执行完继续执行父进程此时子进程执行完了父进程死循环继续执行就导致子进程成为了僵尸进程#includestdio.h #include sys/types.h #include unistd.h #include signal.h #includestdlib.h #include sys/wait.h void myfun(int signum) { int i 0; while(i 5) { printf(receive signum is %d,i%d\n,signum,i); sleep(1); i; } } void myfun1(int signum) { printf(child signal\n); wait(NULL); } int main() { pid_t pid; pid fork(); if(pid0) { int i 0; signal(10,myfun); signal(17,myfun1); while(1) { printf(process i%d\n,i); sleep(1); i; } } if(pid 0) { sleep(3); kill(getppid(),10); sleep(6); exit(0);//kill(getppid(),17) } return 0; }子进程退出发送了一个17号信号父进程接收到17号信号开始执行myfun1也就回收了子进程

更多文章