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. */

我试图编写一个信号处理程序来捕获任意数量的连续SIGINT信号,并防止程序退出。该程序是一个简单的文件服务器。处理程序设置一个全局标志,使接受新连接的while循环结束,对pthread_exit()的调用确保main在退出之前让当前连接完成。当我按下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) */
}
我先用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组
系统调用中被停止,请查看其来源(使用GDB
where
命令)

更新:

考虑到您发布的新代码,不清楚您在哪里调用
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组
系统调用中被停止,请查看其来源(使用GDB
where
命令)

更新:

考虑到您发布的新代码,不清楚您在哪里调用
pthread_exit
以“确保main在退出之前让当前连接完成”。如前所述,主线程将在第一个Control-C上退出循环,并继续调用
exit
,它不会等待其他线程完成


要么你没有显示你的实际代码,要么“第二个控件-C”是一条红鲱鱼,你的第一个控件-C已经带你出去了(没有完成其他线程中的工作)。

注意:这主要是猜测

我很确定在主线程中调用pthread_exit是个坏主意。如果主线程退出,那么操作系统可能会尝试向其他线程发送后续信号

我建议不要在主线程中使用pthread_exit,只需pthread_join()所有其他线程,然后正常退出即可

但是,确保其他线程没有收到信号也很重要。通常,这是通过sigprocmask(或者更准确地说是pthread_sigmask,在Linux下是相同的)来完成的,以屏蔽工作线程中的信号。这确保了信号永远不会传递给他们

注意,为了避免争用条件,您应该在创建子线程之前在主线程中使用pthread_sigmask,然后将