信号处理程序如何在不向signalhandler()函数传递参数的情况下在main()中接收信号号
例如,在下面的main()内部源代码中,传递信号系统调用的第二个参数为signalhandler,而信号处理程序中没有任何参数,但是在进行signalhandler定义时,它正在收集一个名为sig_num的参数.
实际上,这是怎么可能的?
根据ANSI C,如果我们不传递任何参数,那么函数定义就不应该收集任何参数。
请在这件事上帮我。
#include<stdio.h>
#include<signal.h>
void signalhandler(int sig_num)
{
printf("caught signal number: %d\n", sig_num);
}
int main(void)
{
while(1)
{
printf("hello world\n");
sleep(1);
signal(SIGINT, signalhandler);
}
}发布于 2016-05-27 07:50:38
当您将函数signalhandler作为signal(2)的参数时,它不会被调用。原型是:
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);所以你可以看到第二个参数是一个函数指针。您的函数signalhandler稍后将被调用(当信号传递时),调用它的代码将给它一个int参数。
看看其他一些函数指针示例,以更好地理解这种回调机制。
发布于 2016-05-27 07:59:30
signal API注册提供的函数指针,以便在接收到指定信号时调用。可以针对多个信号注册相同的函数指针,因此当调用该函数时将提供接收到的信号值。
在Linux (以及我所知道的所有操作系统)中,信号传递与进程的执行是异步的,并且通知是即时的。操作系统的行为就好像它抢占了程序,并将信号处理程序函数调用注入到程序当前正在执行的任何操作之上。操作系统知道传递了哪个信号,并将其作为参数传递给函数调用。
注意:可以使用
raise生成程序的同步信号。但是,它通常使用OS服务将其传递给进程,而不是直接调用信号处理程序。
如果使用调试器并在信号处理程序中设置断点,并传递适当的信号,您可能会看到回溯跟踪将显示信号处理程序是由操作系统注入的。
例如,考虑一下程序:
void signalhandler (int sig)
{
write(2, "signal!\n", 8);
}
void foo (void)
{
for (;;) {}
}
int main (void)
{
signal(SIGINT, signalhandler);
foo();
}在gdb中运行程序时,可以使用signal命令传递信号。生成的回跟踪结果如下所示:
(gdb) signal SIGINT
Continuing with signal SIGINT.
Breakpoint 1, signalhandler (sig=2) at s.c:5
5 write(2, "signal!\n", 8);
(gdb) bt
#0 signalhandler (sig=2) at s.c:5
#1 <signal handler called>
#2 foo () at s.c:10
#3 0x08048498 in main () at s.c:16注意:重要的是要认识到,信号处理程序函数调用不应被视为常规函数调用。由于操作系统注入了调用,因此有一些限制将在下面讨论。
信号调用可以在代码执行中的任意位置注入。因此,POSIX要求从信号处理程序调用某些函数是安全的。不设计为可重入者的函数如果被信号处理程序函数的注入调用所中断,则有可能处于不一致的状态,而信号处理程序函数又会调用中断的函数。
作为可能发生的问题的一个例子,假设您正在编写操作数据结构的代码,例如从链接列表中删除节点。但是,如果在发送信号时元素的指针没有完全固定,那么信号处理程序可能会看到一个损坏的链接列表。这种情况可能比您想象的更频繁,特别是当您调用一个需要堆分配的函数时。
因此,使信号处理程序变得简单通常是最安全的。例如,信号处理程序可以简单地设置一个标志,然后应用程序代码将需要代码来检测是否设置了标志。
发布于 2016-05-27 08:57:47
我会简单地解释。
信号是向程序传递信息的方式。例如,当程序在终端窗口中运行,然后按Ctrl+C,则终端窗口将SIGINT发送给程序。
现在,对于每个进程,内核维护一个表,该表从每个信号映射到接收信号时要调用的内容。默认情况下,在SIGINT上,行为设置为终止。但是,程序可以通过调用函数信号来更改某些信号的默认行为。
例如:signal(SIGINT, funcHandler)将接收SIGINT时的行为从终止更改为调用funcHandler。但它从来不叫funcHandler。当程序接收到SIGINT时,将调用funcHandler。
现在,当程序接收到SIGINT时,内核查找表以决定调用哪个函数(例如处理程序),然后内核以接收到的信号作为参数设置处理程序堆栈,然后返回到程序。funcHandler是以signal_number作为程序上下文中的参数来调用的。
https://stackoverflow.com/questions/37477039
复制相似问题