1. 信号(signal)
信号是进程间通信的一种方式,这种方式没有传输用户数据,只是在内核中传一个信号(整数),信号的本质是一个整数值
不同的信号值(整数),代表不同的含义(OS设定好的),当然用户可以自定义信号,自定义信号的含义和值由程序员来决定和解释
man -a signalSignal(名称) Value(整数值) Action(动作) Comment(注释) ────────────────────────────────────────────────────────────────────── SIGHUP 1 Term Hangup detected on controlling terminal or death of controlling process // Term:Termination 终止 /* 注释:控制终端的挂起操作,或者是控制终端进程死亡时,依附于控制终端的所有进程 都会收到SIGHUP信号 */ SIGINT 2 Term Interrupt from keyboard /* 注释:从键盘上收到的中断信号,CTRL + C Ctrl + C,发一个SIGINT的信号给占用控制台的进程 */ SIGQUIT 3 Core Quit from keyboard // Core:保存当时进程的上下文信息(产生core文件),然后终止 /* 注释:从键盘上收到的退出信号 Ctrl + \ */ SIGILL 4 Core Illegal Instruction /* 注释:非法指令 */ SIGABRT 6 Core Abort signal from abort(3) /* 注释:调用abort这个函数的时候,进程会收到SIGABRT这个信号 */ SIGFPE 8 Core Floating-point exception /* 注释:浮点数运算异常的时候,进程会收到SIGAFPE这个信号 */ SIGKILL 9 Term Kill signal SIGSTOP 17,19,23 Stop Stop process /* 注释:无条件终止进程,不可修改默认操作(不可以被捕捉) */ SIGSEGV 11 Core Invalid memory reference /* 注释:非法内存访问时,会收到SIGSEGV这个信号 ========> Segamation fault */ SIGPIPE 13 Term Broken pipe: write to pipe with no readers; see pipe(7) /* 注释:当你往一个管道写数据的时候,没有读端进程,就会产生这个SIGPIPE信号 */ SIGALRM 14 Term Timer signal from alarm(2) /* 注释:定时信号,在进程调用alarm时,就会在"闹钟"超时的时候,产生SIGALRM信号 */ SIGTERM 15 Term Termination signal /* 注释:终止信号 */ SIGUSR1 30,10,16 Term User-defined signal 1 SIGUSR2 31,12,17 Term User-defined signal 2 /* 注释:用户自定义信号,由程序员自己设定 */ SIGCHLD 20,17,18 Ign Child stopped or terminated // Ign:默认行为是忽略这个信号 /* 注释:当子进程停止或者终止时,父进程会收到这个信号 */ SIGCONT 19,18,25 Cont Continue if stopped SIGTSTP 18,20,24 Stop Stop typed at terminal SIGTTIN 21,21,26 Stop Terminal input for background process SIGTTOU 22,22,27 Stop Terminal output for background process ......进程在收到一个信号的时候,通常会有三种处理方式:
(1)捕捉信号
把一个信号和用户自定义的信号处理函数关联起来,那么进程在收到该信号的时候,就会自行调用该处理函数
(2)默认行为
进程收到一个信号时,采用操作系统默认的行为,大部分信号的默认行为,会把进程给终止
(3)忽略该信号
2. 信号的处理过程
通过"软中断"来实现的
用户态:程序在执行用户自己的代码
内核态:执行OS的代码
3. linux下信号相关的 API 函数
(1)发送信号 kill
指令:kill -9 pid
NAME kill - send signal to a process SYNOPSIS #include <sys/types.h> #include <signal.h> // kill是用来把一个信号发送到一个指定的进程或者多个进程 int kill(pid_t pid, int sig); pid:指定信号的接收者进程(可能是多个进程) pid > 0:pid就表示接收者的进程号 pid == 0:发送信号给调用者进程同组的所有进程 pid == -1:发送给所有进程(有权限发送的所有进程) pid < -1:发送信号给组id等于pid绝对值的所有进程 sig:你要发送的信号的值 返回值: 成功(至少有一个进程成功的收到信号)返回0 失败返回-1,同时errno被设置#include <stdio.h> #include <sys/types.h> #include <signal.h> #include <unistd.h> int main() { sleep(5); // 5秒后杀死自己 // kill(0, SIGKILL); kill(getpid(), SIGKILL); while (1); return 0; }(2)发送信号给自己 raise
信号处理完后(自己设置信号处理函数),raise才会返回
NAME raise - send a signal to the caller SYNOPSIS #include <signal.h> // raise用来发送信号给调用者本身 int raise(int sig); sig:你要发送的信号的值 raise(sig); <=====> kill(getpid(), sig); 信号处理完后(自己设置信号处理函数),raise才会返回 返回值: 成功返回0 失败返回一个非0的数alarm:定时发送一个闹钟信号(SIGALRM)给调用者进程#include <stdio.h> #include <sys/types.h> #include <signal.h> #include <unistd.h> int main() { sleep(5); // 5秒后杀死自己 raise(SIGKILL); while (1); return 0; }"闹钟":每一个进程都有一个属于自己的“闹钟”,设定的时间到了,进程会收到SIGALRM这个信号,把进程干掉,但是一个进程永远只有一个闹钟生效
NAME alarm - set an alarm clock for delivery of a signal SYNOPSIS #include <unistd.h> // alarm用来给调用者进程的“闹钟”定时 unsigned int alarm(unsigned int seconds); seconds:设置“闹钟”的超时时间,单位为秒 如:alarm(10); // 10秒后,进程就会收到“闹钟”信号 设置一个“闹钟”的超时时间,会自动的把上一次设置的“闹钟”取消 seconds == 0 取消闹钟 返回值: 返回上一个闹钟的剩余秒数 一个进程同一时刻只有一个闹钟#include <stdio.h> #include <unistd.h> int main() { alarm(10); // 10秒后给调用者进程一个闹钟信号 sleep(3); int r = alarm(3); // 重新设定超时时间 printf("r = %d\n", r); while (1); return 0; } r = 7 闹钟#include <stdio.h> #include <unistd.h> int main() { // 看门狗的设置 5s ----> 应当要在5s之内重新设置闹钟(喂狗) alarm(5); printf("Alarm was set\n"); while (1) { sleep(4); // 喂狗 alarm(5); } return 0; }大部分信号的默认行为,就是把收到信号的进程给干掉,在实际应用的时候,我们一般会修改默认行为(当条件发送的时候,做指定的任务)
改变信号的处理方式 -----> 捕捉信号本质就是将信号处理函数向量表中对应的函数地址替换成了自定义的函数地址
(3)捕捉信号:改变信号的处理方式 signal
把具体的信号与具体的处理方式相关联,关键是将原先系统默认的行为(函数地址)替换为用户自定义的函数 --- signal
SIGKILL 9 Term Kill signal SIGSTOP 17,19,23 Stop Stop process /* 注释:无条件终止进程,不可修改默认操作(不可以被捕捉) */NAME signal - ANSI C signal handling SYNOPSIS #include <signal.h> typedef void (*sighandler_t)(int); 定义了一个类型,类型名字是sighandler_t typedef:定义一个已有类型的别名 sighandler_t是一个函数指针类型,可以定义指针变量,指向一个函数 (保存一个函数的地址) 指向的函数的类型为: 无返回值,带一个int类型的参数 实际上就是指向收到signum后要执行的信号处理函数 sighandler_t signal(int signum, sighandler_t handler); signum:要捕捉的信号的值 handler:函数地址,对应的函数:无返回值,且参数为int类型 收到signum后的处理方式,有以下三种: 1.你自己写一个信号处理函数 void my_handler(int sig) { .... } 2.忽略该信号 SIG_IGN 3.采用操作系统的默认处理方式 SIG_DFL 返回值: 成功返回上一次的处理方式的函数指针 失败,返回SIG_ERR,同时errno被设置#include <stdio.h> #include <signal.h> #include <unistd.h> // 自定义的信号处理方式 void my_handler(int sig) { printf("sig = %d\n", sig); printf("haha,you not kill me\n"); } int main() { signal(SIGALRM, my_handler); alarm(5); while (1); return 0; }练习:
通常情况下,一个占用终端的进程在按 Ctrl+C 的时候会被杀死,现在请写一个代码,这个程序在按 Ctrl+C后不会被杀死#include <stdio.h> #include <signal.h> #include <unistd.h> // 自定义的信号处理方式 void my_handler(int sig) { switch (sig) { case SIGALRM: printf("recive a SIGALRM\n"); break; case SIGINT: // ctrl + C printf("recive a ctrl + C\n"); break; } } int main() { // 改变信号的处理方式 signal(SIGALRM, my_handler); signal(SIGINT, my_handler); // signal(SIGINT, SIG_IGN); // 忽略该信号 alarm(5); // 设置闹钟,不会阻塞 while (1); return 0; }(4)等待信号的到来 pause
信号处理完后(自己设置信号处理函数),才会执行pause
等待信号的到来 pause NAME pause - wait for signal SYNOPSIS #include <unistd.h> 会阻塞调用者进程,直到一个信号处理程序执行完毕后,才会继续运行 int pause(void); 返回值 成功时 pause 函数不返回,因为进程被信号处理程序中断 失败时返回 -1,并将 errno 设置为 EINTR,表示函数因信号中断#include <stdio.h> #include <signal.h> #include <unistd.h> // 自定义的信号处理方式 void my_handler(int sig) { printf("recive a signal: %d\n", sig); alarm(2); } int main() { signal(SIGALRM, my_handler); alarm(2); // 设置闹钟,不会阻塞 while (1) { printf("%d\n", pause()); printf("pause is over\n"); } return 0; } // 一直重复打印以下三条语句 // recive a signal: 14 // -1 // pause is over#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> // 自定义的信号处理方式 void my_handler(int sig) { printf("recive a signal: %d\n", sig); alarm(2); while (1); } int main() { signal(SIGALRM, my_handler); alarm(2); // 设置闹钟,不会阻塞 while (1) { printf("%d\n", pause()); printf("pause is over\n"); } return 0; } // recive a signal: 14 // 阻塞#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> // 自定义的信号处理方式 void my_handler(int sig) { printf("recive a signal: %d\n", sig); alarm(2); exit(0); } int main() { signal(SIGALRM, my_handler); alarm(2); // 设置闹钟,不会阻塞 while (1) { printf("%d\n", pause()); printf("pause is over\n"); } return 0; } // recive a signal: 14


2083

被折叠的 条评论
为什么被折叠?



