如何忽略C中的信号?

时间:2017-11-26 03:27:07

标签: c pthreads signals posix

我想忽略线程生命周期的前100秒的信号,我开发了这个解决方案,但它不起作用,我缺少了什么部分?

问题陈述: 编写一个包含两个线程的程序 - 创建线程(线程A)和创建线程(线程B)。在创建线程B之后,线程A等待线程B终止然后它自己终止。线程B仅在稍后描述的特殊情况下终止。信号SIGINT(ctrl C)在线程B中被阻塞(即,只有线程A处理SIGINT)。每次,用户按下ctrl C,线程A尝试取消线程B.线程B保持等待在其生命的前100秒内收到的任何取消请求。一旦线程B的生命的前100秒结束,任何取消请求都将被尊重。此外,线程B以每10秒后的秒数打印其当前生命周期。

#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <math.h>
#include <time.h>
#include <sys/time.h>

#define handle_error_en(en, msg) \
               do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

void function_to_time(void);


static void *thread_func(void *arg)
{

    struct sigaction act;
    sigaction(SIGINT,NULL,&act);
    act.sa_handler = SIG_IGN;
    sigaction(SIGINT,&act,NULL); 

    sigset_t sigmask;
    sigemptyset(&sigmask);
    sigaddset(&sigmask, SIGALRM);
    sigprocmask(SIG_BLOCK,&sigmask,NULL); 

    sigemptyset(&sigmask);
    sigaddset(&sigmask,SIGALRM);
    sigaddset(&sigmask,SIGINT);

    alarm(100);

    int sigintsReceived = 0;
    int sigalrmsReceived = 0;

    while( 1 == 1)
    {
        int recvdSig;
        sigwait(&sigmask,&recvdSig);

        if( recvdSig == SIGALRM ) 
        {
            if( sigalrmsReceived == 0 )
            {
                sigalrmsReceived++;
                printf("\npthread_cancel is enabled\n");

                sigset_t sigmask2;
                sigemptyset(&sigmask2);
                sigaddset(&sigmask2, SIGINT);
                sigprocmask(SIG_BLOCK,&sigmask2,NULL); 

                sigaction(SIGINT,NULL,&act);
                act.sa_handler = SIG_DFL;
                sigaction(SIGINT,&act,NULL); 
            }

        }
    };

    return 0;
}


int main(void)
{

   sigset_t set;

   pthread_t thr;
   void *res;
   int s;

   s = pthread_create(&thr, NULL, &thread_func, (void *)&set);
   if (s != 0)
       handle_error_en(s, "pthread_create");

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

    int recvdSig;
    sigwait(&set,&recvdSig);

    if( recvdSig == SIGINT ) 
    {
        printf("Signal received\n");
        printf("main(): sending cancellation request\n");
        s = pthread_cancel(thr);

        if (s != 0)
            handle_error_en(s, "pthread_cancel");
    }

    s = pthread_join(thr, &res);
    if (s != 0)
    handle_error_en(s, "pthread_join");

    if (res == PTHREAD_CANCELED)
    printf("main(): thread was canceled\n");
    else
    printf("main(): thread wasn't canceled (shouldn't happen!)\n");
    exit(EXIT_SUCCESS);

}

2 个答案:

答案 0 :(得分:0)

仔细阅读signal(7)&amp; signal-safety(7)。您只能在信号处理程序中使用(直接和间接) async-signal-safe 函数。请注意errno(3)中的EINTR并在每次阻止系统调用后对其进行测试(例如,在read(2) stdio 之后)。

信号和pthreads(7)无法很好地协同工作。信号处理适用于整个过程(不适用于其中的单个线程)。

您可以使用sigprocmask(2),更好的是pthread_sigprocmask(3)

一个常见的技巧是在初始化时将pipe(7)设置为self,在信号处理程序中设置write(2)一个或几个字节,然后poll(2)然后设置read(2)。在Qt文档中,这个技巧是explained

使用调试器gdbstrace(1)调试您的程序。

答案 1 :(得分:0)

  

编写一个有两个线程的程序 - 创建线程(线程A)和   创建线程(线程B)。在创建线程B之后,线程A等待   线程B终止然后终止自身。线程B.   仅在稍后描述的特殊情况下终止。信号   SIGINT(ctrl C)在线程B中被阻止(即只有线程A处理   SIGINT)。每次,用户按下ctrl C,线程A尝试取消   线程B.线程B保持等待收到的任何取消请求   在其生命的前100秒。任何取消请求是   在线程B的生命结束的第一个100秒之后,我很荣幸。   此外,线程B以秒为单位打印其当前生命周期   每10秒钟一次。

如果我理解得很好,你可以试试:

  • 线程B可以屏蔽SIGUSR1和SIGINT(alarm),设置10秒的警报(start)及其打印当前时间的处理程序,计算这些中断的数量,当达到10时,取消屏蔽SIGUSR1。

  • 线程A可以屏蔽SIGUSR1和SIGALRM并捕获SIGINT,当收到SIGINT时,它将在加入线程B时提供所有这一切的SIGUSR1。

在这种情况下,SIGUSR1用作&#34;取消&#34;对于线程B。