In the part 1 of the Linux信号series, we learned about the fundamental concepts behind Linux 信号s.
Building 上 the previous part, in 这个 article we will learn about how to catch 信号s in a process. We will present the practical aspect of 信号 handling using C program code snippets.
捕捉信号
As already discussed in the previous article, If a process wishes to handle certain 信号s then in the code, the process has to register a 信号 handling function to the kernel.
The following is the prototype of a 信号 handling function :
void <signal handler func name> (int sig)
The 信号 handler function has void return type and accepts a 信号 number corresponding to the 信号 that needs to be handled.
To get the 信号 handler function registered to the kernel, the 信号 handler function pointer is passed as second argument to the ‘signal’ function. The prototype of the 信号 function is :
void (*signal(int signo, void (*func )(int)))(int);
这似乎是一个复杂的声明。如果我们尝试对其进行解码:
- 该函数需要两个参数。
- The first argument is an 整型eger (signo) depicting the 信号 number or 信号 value.
- The second argument is a pointer to the 信号 handler function that accepts an 整型eger as argument and returns nothing (void).
- 而‘signal’函数本身返回函数指针,其返回类型为void。
好吧,为了使事情变得简单,让我们使用typedef:
typedef void 西格芬奇(int)
所以,在这里我们做了一个新的类型‘sigfunc’. Now using 这个 typedef, if we redesign the prototype of the 信号 handler :
西格芬奇 *signal(int, 西格芬奇*);
Now we see that its easier to comprehend that the 信号 handler function accepts an 整型eger and a 西格芬奇 type function pointer while it returns a 西格芬奇 type function pointer.
示例C程序来捕获信号
大多数Linux用户使用组合键Ctr + C终止Linux中的进程。
Have you ever thought of what goes behind 这个. Well, whenever ctrl+c is pressed, a 信号 SIGINT is sent to the process. The default action of 这个 信号 is to terminate the process. But 这个 信号 can also be handled. The following code demonstrates 这个 :
#include<stdio.h> #include<signal.h> #include<unistd.h> void sig_handler(int signo) { 如果(signo == SIGINT) 打印 ("received SIGINT\n"); } int main(void) { if (signal(SIGINT, sig_handler) == SIG_ERR) 打印 ("\ncan't catch SIGINT\n"); // A long long wait so that we can easily issue a 信号 to 这个 process while(1) sleep(1); return 0; }
在上面的代码中,我们使用无限while循环模拟了一个长时间运行的过程。
A function sig_handler is used a s a 信号 handler. This function is registered to the kernel 通过 passing it as the second argument of the system call ‘signal’在main()函数中。该函数的第一个参数‘signal’ is the 信号 we 整型end the 信号 handler to handle which is SIGINT in 这个 case.
附带说明一下,使用函数sleep(1)有一个原因。该函数已在while循环中使用,因此while循环会在一段时间后执行(在这种情况下为一秒钟)。这很重要,因为否则,无限期的while循环会疯狂运行,可能会消耗大量CPU,从而使计算机非常缓慢。
无论如何,返回,当进程运行时,我们尝试使用Ctrl + C终止进程:
$ ./sigfunc ^Creceived SIGINT ^Creceived SIGINT ^Creceived SIGINT ^Creceived SIGINT ^Creceived SIGINT ^Creceived SIGINT ^Creceived SIGINT
我们在上面的输出中看到,我们多次尝试了组合键ctrl + c,但是每次该过程’t terminate. This is because the 信号 was handled in the code and 这个 was confirmed from the print we got 上 each line.
SIGKILL,SIGSTOP和用户定义的信号
Apart from handling the standard 信号s(like INT, TERM etc) that are available. We can also have user defined 信号s that can be sent and handled. Following is the code handling a user defined 信号 USR1 :
#include<stdio.h> #include<signal.h> #include<unistd.h> void sig_handler(int signo) { if (signo == SIGUSR1) 打印 ("received SIGUSR1\n"); else if (signo == SIGKILL) 打印 ("received SIGKILL\n"); else if (signo == SIGSTOP) 打印 ("received SIGSTOP\n"); } int main(void) { if (signal(SIGUSR1, sig_handler) == SIG_ERR) 打印 ("\ncan't catch SIGUSR1\n"); if (signal(SIGKILL, sig_handler) == SIG_ERR) 打印 ("\ncan't catch SIGKILL\n"); if (signal(SIGSTOP, sig_handler) == SIG_ERR) 打印 ("\ncan't catch SIGSTOP\n"); // A long long wait so that we can easily issue a 信号 to 这个 process while(1) sleep(1); return 0; }
We see that in the above code, we have tried to handle a user defined 信号 USR1. Also, as we know that two 信号s KILL and STOP cannot be handled. So we have also tried to handle these two 信号s so as to see how the ‘signal’在这种情况下,系统调用会响应。
当我们运行上面的代码时:
$ ./sigfunc can't catch SIGKILL can't catch SIGSTOP
所以上面的输出清楚地表明,只要系统调用‘signal’ tries to register handler for KILL and STOP 信号s, the 信号 function fails indicating that these two 信号s cannot be caught.
Now we try to pass the 信号 USR1 to 这个 process using the 杀死命令:
$ kill -USR1 2678
在运行上述程序的终端上,我们看到:
$ ./sigfunc can't catch SIGKILL can't catch SIGSTOP received SIGUSR1
So we see that the user defined 信号 USR1 was received in the process and was handled properly.
如果您喜欢这篇文章,您可能还会喜欢..
![]() |
![]() |
![]() |
![]() |
谢谢!很棒的帖子!相当讲究和客观。恭喜! --