C 持续信号处理
我试图编写一个信号处理程序来捕获任意数量的连续SIGINT信号,并防止程序退出。该程序是一个简单的文件服务器。处理程序设置一个全局标志,使接受新连接的while循环结束,对pthread_exit()的调用确保main在退出之前让当前连接完成。当我按下ctrl-C键一次时,一切都像发条一样进行,但第二次则立即退出程序C 持续信号处理,c,linux,pthreads,signals,C,Linux,Pthreads,Signals,我试图编写一个信号处理程序来捕获任意数量的连续SIGINT信号,并防止程序退出。该程序是一个简单的文件服务器。处理程序设置一个全局标志,使接受新连接的while循环结束,对pthread_exit()的调用确保main在退出之前让当前连接完成。当我按下ctrl-C键一次时,一切都像发条一样进行,但第二次则立即退出程序 int serverStop = 0; ... int main() { /* set up the server -- socket(), bind() etc. */
int serverStop = 0;
...
int main()
{
/* set up the server -- socket(), bind() etc. */
struct sigaction sigint_hadler;
sigint_handler.sa_handler = catch_sigint;
sigint_handler.sa_flags = 0;
sigemptyset(&sigint_handler.sa_mask);
sigaction(SIGINT, &sigint_handler, NULL);
/* signal(SIGINT, catch_sigint); */
while(serverStop == 0)
{
/* accept new connections and pthread_create() for each */
}
pthread_exit(NULL);
}
...
static void catch_sigint(int signo)
{
serverStop = 1;
/* signal(SIGINT, catch_sigint) */
}
我先用signal()进行了尝试:
我还尝试使用sigaction:
struct sigaction sigint_handler;
sigint_handler.sa_handler = catch_sigint;
sigemptyset(&sigint_handler.sa_mask);
sigint_handler.sa_flags = 0;
sigaction(SIGINT, &sigint_handler, NULL);
不确定如何“重新安装”这一个,我只是在处理程序中复制了这段代码,类似于使用signal()方法的处理程序
这两种方法都没有我想象的那么有效
其他信息: 该程序是一个简单的文件服务器。它接收来自客户端的请求,该请求只是由请求的文件名组成的字符串。它利用pthread,以便可以同时进行传输。收到SIGINT后,我希望服务器退出while循环,等待所有当前传输完成,然后关闭。同样,无论我如何编写信号处理程序,第二个SIGINT都会立即终止程序
int serverStop = 0;
...
int main()
{
/* set up the server -- socket(), bind() etc. */
struct sigaction sigint_hadler;
sigint_handler.sa_handler = catch_sigint;
sigint_handler.sa_flags = 0;
sigemptyset(&sigint_handler.sa_mask);
sigaction(SIGINT, &sigint_handler, NULL);
/* signal(SIGINT, catch_sigint); */
while(serverStop == 0)
{
/* accept new connections and pthread_create() for each */
}
pthread_exit(NULL);
}
...
static void catch_sigint(int signo)
{
serverStop = 1;
/* signal(SIGINT, catch_sigint) */
}
我不认为任何其他代码可能是相关的,但请随意要求详细说明我不确定是否理解。信号处理程序通常不应重新安装任何信号处理程序(包括其自身),因为在安装另一个信号处理程序之前,该信号处理程序一直处于运行状态。另请参见
SA_NODEFER
标志,以便能够在信号处理期间捕获信号
信号处理器应该是短的。看看我对你的回答。它通常主要设置一个易失性sig_原子\u t
变量
什么不起作用?不要在信号处理程序中进行复杂或持久的处理。
请出示您的代码…我不太清楚。信号处理程序通常不应重新安装任何信号处理程序(包括其自身),因为在安装另一个信号处理程序之前,该信号处理程序一直处于运行状态。另请参见
SA_NODEFER
标志,以便能够在信号处理期间捕获信号
信号处理器应该是短的。看看我对你的回答。它通常主要设置一个易失性sig_原子\u t
变量
什么不起作用?不要在信号处理程序中进行复杂或持久的处理。
请显示您的代码…在Linux上,您不必使用
signal
(默认设置)或sigaction
重新安装信号处理程序
当我按ctrl-C键一次但第二次时,程序立即退出
int serverStop = 0;
...
int main()
{
/* set up the server -- socket(), bind() etc. */
struct sigaction sigint_hadler;
sigint_handler.sa_handler = catch_sigint;
sigint_handler.sa_flags = 0;
sigemptyset(&sigint_handler.sa_mask);
sigaction(SIGINT, &sigint_handler, NULL);
/* signal(SIGINT, catch_sigint); */
while(serverStop == 0)
{
/* accept new connections and pthread_create() for each */
}
pthread_exit(NULL);
}
...
static void catch_sigint(int signo)
{
serverStop = 1;
/* signal(SIGINT, catch_sigint) */
}
这并不是因为你的处理器被重置了,而是因为你的信号处理器正在做一些它不应该做的事情
下面是我调试这个问题的方法:在GDB下运行程序,然后
(gdb) catch syscall exit
(gdb) catch syscall exit_group
(gdb) run
现在等待程序开始工作,然后点击Control-C。这将给您(gdb)
提示。现在继续该程序,就像它已接收到SIGINT
:signal-SIGINT
(这将调用您的处理程序)。再次重复“控制C/信号信号输入”顺序。如果您在exit
或exit\u组
系统调用中被停止,请查看其来源(使用GDBwhere
命令)
更新:
考虑到您发布的新代码,不清楚您在哪里调用pthread_exit
以“确保main在退出之前让当前连接完成”。如前所述,主线程将在第一个Control-C上退出循环,并继续调用exit
,它不会等待其他线程完成
要么您没有显示实际的代码,要么“第二个Control-C”是一个令人费解的问题,您的第一个Control-C已经带您出去了(没有完成其他线程中的工作)。在Linux上,您不必使用
signal
(默认情况下)或sigaction
重新安装信号处理程序
当我按ctrl-C键一次但第二次时,程序立即退出
int serverStop = 0;
...
int main()
{
/* set up the server -- socket(), bind() etc. */
struct sigaction sigint_hadler;
sigint_handler.sa_handler = catch_sigint;
sigint_handler.sa_flags = 0;
sigemptyset(&sigint_handler.sa_mask);
sigaction(SIGINT, &sigint_handler, NULL);
/* signal(SIGINT, catch_sigint); */
while(serverStop == 0)
{
/* accept new connections and pthread_create() for each */
}
pthread_exit(NULL);
}
...
static void catch_sigint(int signo)
{
serverStop = 1;
/* signal(SIGINT, catch_sigint) */
}
这并不是因为你的处理器被重置了,而是因为你的信号处理器正在做一些它不应该做的事情
下面是我调试这个问题的方法:在GDB下运行程序,然后
(gdb) catch syscall exit
(gdb) catch syscall exit_group
(gdb) run
现在等待程序开始工作,然后点击Control-C。这将给您(gdb)
提示。现在继续该程序,就像它已接收到SIGINT
:signal-SIGINT
(这将调用您的处理程序)。再次重复“控制C/信号信号输入”顺序。如果您在exit
或exit\u组
系统调用中被停止,请查看其来源(使用GDBwhere
命令)
更新:
考虑到您发布的新代码,不清楚您在哪里调用pthread_exit
以“确保main在退出之前让当前连接完成”。如前所述,主线程将在第一个Control-C上退出循环,并继续调用exit
,它不会等待其他线程完成
要么你没有显示你的实际代码,要么“第二个控件-C”是一条红鲱鱼,你的第一个控件-C已经带你出去了(没有完成其他线程中的工作)。注意:这主要是猜测 我很确定在主线程中调用pthread_exit是个坏主意。如果主线程退出,那么操作系统可能会尝试向其他线程发送后续信号 我建议不要在主线程中使用pthread_exit,只需pthread_join()所有其他线程,然后正常退出即可 但是,确保其他线程没有收到信号也很重要。通常,这是通过sigprocmask(或者更准确地说是pthread_sigmask,在Linux下是相同的)来完成的,以屏蔽工作线程中的信号。这确保了信号永远不会传递给他们 注意,为了避免争用条件,您应该在创建子线程之前在主线程中使用pthread_sigmask,然后将