C 如何创建用于信号处理的线程,并在接收到信号后退出进程?

C 如何创建用于信号处理的线程,并在接收到信号后退出进程?,c,linux,signals,C,Linux,Signals,我编写了以下代码来处理单独线程中的信号,以强制清理一些资源并退出整个过程 下面是关于下面代码的简要说明 当接收到信号时,setvolatile sig_atomic_t sig_set_flag=1内部信号处理程序 在信号处理器线程中,检查循环中的sig set标志值 if(sig\u set\u flag==1)从信号处理器线程发送类似“我要下楼”的通知,并调用退出(0)来自线程 进程中的任何线程都可以接收信号。所以我设置了全局变量 我有两个问题 1) 这个实现很好吗?或者我必须阻止主线程

我编写了以下代码来处理单独线程中的信号,以强制清理一些资源并退出整个过程

下面是关于下面代码的简要说明

  • 当接收到信号时,setvolatile sig_atomic_t sig_set_flag=1内部信号处理程序
  • 在信号处理器线程中,检查循环中的sig set标志值
  • if(sig\u set\u flag==1)信号处理器线程发送类似“我要下楼”的通知,并调用退出(0)来自线程
进程中的任何线程都可以接收信号。所以我设置了全局变量

我有两个问题

1) 这个实现很好吗?或者我必须阻止主线程的信号并仅由生成的线程处理

2) 如何阻止主进程的信号并在线程中处理它

#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

/*
 * Set this variable if any signal is received
 */
volatile sig_atomic_t sig_set_flag = 0;

pthread_mutex_t cleanup_mutex;

/*
 * Resource cleanup function.
 */
int cleaup_resources() {

    pthread_mutex_lock(&cleanup_mutex);
    /*  
     * Send notification to all the clients.
     * Delete all the temp files
     */
    printf("Notified to clients.Exiting process\n");
    pthread_mutex_unlock(&cleanup_mutex);

    return 0;
}

/*
 * Signal handler thread
 */
void sig_term_handler(int sig_num) {
  sig_set_flag = sig_num;    
}


/*
 * Signal handler thread routine
 */
void *signal_handler_thread(void * args) {
    while(1) {
         if(sig_set_flag != 0) {
             printf("%s : Signal flag is set for sig_no %d\n",__func__,sig_set_flag);
             cleaup_resources();
             break;
         }
         usleep(5);
    }
    exit(0);
}

int main()
{
    int loop_count,status;
    pthread_t tid;
    pid_t pid;
    struct sigaction sig;
    sig.sa_handler = &sig_term_handler;
    sig.sa_flags = 0;
    sigaction(SIGTERM, &sig, NULL);

    /*
     * Spawn a thread to monitor signals.
     * If signal received, Exit the process.
     */

    pthread_create(&tid, NULL, signal_handler_thread, NULL);


    while(1) {
     printf("Some time consuming task in progress... PID = %d\n",getpid());
     pid = fork();
     if(pid == 0) {

         sleep(100);
         return 0;
     } else {
     waitpid(pid, &status, 0);
     loop_count++;
     if( loop_count>=10)
        break;
     }
    }
    cleaup_resources();
    exit(0);

}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
/*
*如果收到任何信号,则设置此变量
*/
易失性信号原子信号集标志=0;
pthread_mutex_t cleanup_mutex;
/*
*资源清理功能。
*/
int cleaup_资源(){
pthread_mutex_lock(&cleanup_mutex);
/*  
*向所有客户端发送通知。
*删除所有临时文件
*/
printf(“已通知客户端。正在退出进程\n”);
pthread_mutex_unlock(&cleanup_mutex);
返回0;
}
/*
*信号处理器线程
*/
无效符号项处理程序(int sig_num){
sig_set_flag=sig_num;
}
/*
*信号处理器线程例程
*/
void*信号处理程序线程(void*args){
而(1){
如果(信号设置标志!=0){
printf(“%s:信号标志已为信号编号%d\n设置”,\uuuuu func\uuuuu,信号设置\u标志);
cleaup_resources();
打破
}
usleep(5);
}
出口(0);
}
int main()
{
int loop_计数、状态;
pthread_t tid;
pid_t pid;
结构sig动作sig;
sig.sa_handler=&sig_term_handler;
sig.sa_标志=0;
sigation(SIGTERM,&sig,NULL);
/*
*生成一个线程来监视信号。
*如果收到信号,则退出该过程。
*/
pthread\u create(&tid,NULL,signal\u handler\u thread,NULL);
而(1){
printf(“正在进行一些耗时的任务…PID=%d\n”,getpid());
pid=fork();
如果(pid==0){
睡眠(100);
返回0;
}否则{
waitpid(pid和status,0);
循环计数++;
如果(循环计数>=10)
打破
}
}
cleaup_resources();
出口(0);
}
注意:我知道信号会中断一些系统调用,并且会设置EINTR。不幸的是,某些系统调用(即waitpid()不会被中断。所以我产生了一个线程来处理这个场景。

1)您的实现似乎是正确的
signal()
sigaction()
为整个进程注册一个处理函数,因此在主线程或派生线程中调用它们并不重要

2) 要在主线程中阻止信号并在线程中处理它,必须使用
sigwait()
sigwaitinfo()
设计处理程序线程,而不是处理程序函数。因此线程将等待信号,程序执行不会中断

在这种情况下,必须在所有线程(包括主线程)中阻止进程范围的信号。如果未被阻止,信号将在程序上具有默认行为

必须使用
pthread\u sigmask()
来阻止一个或多个信号。阻止SIGTERM的代码示例:

sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGTERM);
pthread_sigmask(SIG_BLOCK,&set,NULL);
创建线程时,它会继承创建者线程的阻塞信号

我修改了您的代码,向您展示了如何使用
sigwaitinfo()
pthread\u sigmask()

#包括
#包括
#包括
#包括
#包括
#包括
#包括
pthread_mutex_t cleanup_mutex;
/*
*资源清理功能。
*/
int cleaup_资源(){
pthread_mutex_lock(&cleanup_mutex);
/*  
*向所有客户端发送通知。
*删除所有临时文件
*/
printf(“已通知客户端。正在退出进程\n”);
pthread_mutex_unlock(&cleanup_mutex);
返回0;
}
/*
*信号处理器线程例程
*/
void*信号处理程序线程(void*args){
sigset\u t集;
sigpemptyset(&set);
sigaddset(&set,SIGINT);
siginfo_t info;
而(1){
sigwaitinfo(设置和信息(&S);
if(info.si_signo==SIGINT){
printf(“\n收到的签名\n”);
cleaup_resources();
出口(0);
}      
}
}
int main()
{
int loop_计数、状态;
pthread_t tid;
pid_t pid;
sigset\u t集;
sigpemptyset(&set);
sigaddset(&set,SIGINT);
pthread_sigmask(SIG_块,&set,NULL);
//新线程将继承被阻止的线程
//来自创建它的线程的信号:
pthread\u create(&tid,NULL,signal\u handler\u thread,NULL);
而(1){
printf(“正在进行一些耗时的任务…PID=%d\n”,getpid());
pid=fork();
如果(pid==0){
睡眠(100);
返回0;
}否则{
waitpid(pid和status,0);
循环计数++;
如果(循环计数>=10)
打破
}
}
cleaup_resources();
出口(0);
}

另外,请注意
fork()
,根据我所做的测试,子进程将继承阻塞的信号。

能否避免显式清理资源?我问这个问题是因为这总是一件痛苦的事情,需要持续的测试/调试/验证,而且通常是可以避免的,例如“删除所有临时文件”-你不能在启动时删除它们吗?毕竟,在“kill-9”或电源故障时,您的清理尝试将失败。对不起,您是说
waitpid
不能被信号中断吗?EINTR是一种记录在案的错误情况,如果所有信号的PID不会被中断。(即)SIGHUP不会打断waitpid。@NaveenKumar,我们是bi
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>

pthread_mutex_t cleanup_mutex;

/*
 * Resource cleanup function.
 */
int cleaup_resources() {

    pthread_mutex_lock(&cleanup_mutex);
    /*  
     * Send notification to all the clients.
     * Delete all the temp files
     */
    printf("Notified to clients.Exiting process\n");
    pthread_mutex_unlock(&cleanup_mutex);

    return 0;
}

/*
 * Signal handler thread routine
 */
void *signal_handler_thread(void * args) {
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set,SIGINT);
    siginfo_t info;
    while(1) {
      sigwaitinfo(&set,&info);
      if(info.si_signo == SIGINT){
        printf("\nSIGINT received\n");
        cleaup_resources();
        exit(0);
      }      
    }
}

int main()
{
    int loop_count,status;
    pthread_t tid;
    pid_t pid;

    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set,SIGINT);
    pthread_sigmask(SIG_BLOCK,&set,NULL);

    // The new thread will inherit the blocked 
    // signals from the thread that create it:
    pthread_create(&tid, NULL, signal_handler_thread, NULL);


    while(1) {
     printf("Some time consuming task in progress... PID = %d\n",getpid());
     pid = fork();
     if(pid == 0) {

         sleep(100);
         return 0;
     } else {
     waitpid(pid, &status, 0);
     loop_count++;
     if( loop_count>=10)
        break;
     }
    }
    cleaup_resources();
    exit(0);

}