【问题标题】:How to Ignore Signal in C?如何在 C 中忽略信号?
【发布时间】:2017-11-26 03:27:07
【问题描述】:

我想在线程生命周期的前 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);

}

【问题讨论】:

  • 哪一部分不工作?
  • 它没有忽略信号
  • @June 不忽略是什么意思? SIGINT 的默认行为是终止您的程序,如果没有发生,您的信号掩码有效。但是,您应该考虑到信号中断阻塞命令、唤醒进程(它们中断读取、睡眠或等待),这是无法避免的。看看你的返回值,是不是 EINTR (-4)?
  • 此外,信号和信号处理程序适用于您的整个进程,而不是每个线程。任何线程都可以处理信号,但通常由主线程处理
  • @immortal 而pthread_sigmask(3)呢?

标签: c pthreads signals posix


【解决方案1】:

仔细阅读signal(7) & 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) 调试您的程序。

【讨论】:

    【解决方案2】:

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

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

      1234563到达取消屏蔽 SIGUSR1。
    • 线程 A 可以屏蔽 SIGUSR1 和 SIGALRM 并捕获 SIGINT,当收到 SIGINT 时,它会在加入线程 B 的同时传递所有这一切。

    在这种情况下,SIGUSR1 被用作线程 B 的“取消”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-28
      • 1970-01-01
      相关资源
      最近更新 更多