信号处理程序和多线程

signal handler and multithreading

本文关键字:多线程 程序 信号处理      更新时间:2023-10-16

我知道信号是CPU和OS内核之间通信的一种方式。信号可以中断指令的顺序,执行处理程序并返回指令序列。

这是此链接的描述:

当被捕获的信号由过程处理时,正常 该过程执行的指令顺序是暂时的 被信号处理程序中断。然后该过程继续 执行,但是信号处理程序中的说明现在为 执行。如果信号处理程序返回,则该过程继续 执行正常的指令序列,它正在执行 抓住了信号。

这是我的测试:

void func(int p)
{
    cout<<"int"<<endl;
    sleep(5);
}
int main()
{
    signal(SIGINT, func);
    while(1)
    {
        cout<<"main"<<endl;
        sleep(2);
    }   
    return 0;
}

我执行它,如果我按ctrl+Cint将打印,然后我必须等待5秒钟,无论我在等待5秒时按了多少次ctrl+C,什么也没发生。

然后我进行另一个测试:

void func(int p)
{
    cout<<"int"<<endl;
    sleep(5);
}
int main()
{
    signal(SIGINT, func);
    thread t1([](){while(1){cout<<"t1"<<endl; sleep(2);}});
    thread t2([](){while(1){cout<<"t2"<<endl; sleep(2);}});
    t1.join();
    t2.join();
    return 0;
}

对于此代码,我发现我可以连续按ctrl+C,并打印三个int,然后我必须等待大约5秒钟。

因此,似乎第一个ctrl+C中断t1线程,第二个中断t2线程,第三个线程中断主线程。

因此,如果有多线程?

简介

首先,每个线程都有自己的掩码,指定了它正在听的信号。创建线程时,它继承了正在创建它的线程的掩码(让我称其为 parent thread)pthread_create被称为active。

通常,如果线程正在收听信号,那么除非您想拥有许多执行相同功能的线程(例如,在处理服务器中的连接请求以同时处理许多请求时)。这样,您始终知道哪个线程函数正在处理信号。否则,您将不知道给定信号执行哪个线程函数,因此无法调试(一个例子是您自己的问题)。

更改正在从 parent thread 创建的 child thread 的掩码您创建一个新的掩码,您将其设置为"活动",使用pthread_create创建一个新线程,然后在 parent thread 中再次设置上一个蒙版活动(请参阅答案末尾的代码)。

编辑:根据这篇文章,最好使用sigaction()而不是signal。在现代系统中,signal()使用sigaction()实施,因此没有任何区别。但是,如果使用旧实现,可能会出现问题。

答案

因此,如果在那里,信号仅中断线程而不是整个过程是多线程吗?

no :信号只是信号,它们什么都不做。与信号相关的操作有能力做事,包括停止程序或终止线程。每个信号都有关联的默认操作,并且SIGINT的默认操作是中断过程。

使用您的处理程序,您正在覆盖默认操作。因此,它将不再停止程序,但会执行您在线程函数中指定的内容。

在第一种情况下,您只有一个线程,一个主线,即无限循环,只要他活着,它总是会捕获信号,这就是为什么行为的原因。如果您重新发出信号,则暂时阻止信号,直到信号处理程序结束执行。但是,如果处理程序执行时发送了许多信号,则可以松散一些信号。实际上,如这里所述,被阻塞的信号设置为待处理,但没有排队。术语待处理表示操作系统记得有一个信号等待下一个机会通过设置标志来交付,而 not eqeued 表示它可以通过在某个地方设置旗帜,但不能保留有多少信号到达的确切记录。因此,如果信号是发送一次,5次或更多(尝试使用您的程序按CTRL C的更多次:我已经尝试过),而信号处理程序执行它会产生完全相同的行为。

在您的第二种情况下,您有3个线程:main ONE,t1t2:所有这些线程都可以看到信号SIGINT,并且所有这些都与同一信号处理程序相关联。如果您将三次按下3次,那么所有三个都将执行处理程序:这就是为什么您看不到任何延迟的原因。如果您按非常非常快的速度,并且超过3次(收听该信号的线程数),我认为您会看到与第一个行为类似的东西。

我将以我在设置口罩的问题中发布的代码结束答案,以便仅由主线程捕获一些信号:

int main()
{
    int err;
    sigset_t omask, mask;
    pthread_t thread_motionSensor;
    pthread_t thread_tempReading;
    pthread_t thread_platformPost;
    printf("Created threads IDsn");
    ...
    if (signal(SIGINT, sig_handler)==SIG_ERR)
        printf("Error on recording SIGINT HANDLERn");
    /*Create a new mask to block all signals for the following thread*/
    sigfillset(&mask);
    pthread_sigmask(SIG_SETMASK, &mask, &omask);
    printf("Trying to create threadsn");
    if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
    {
    printf("Thread 1 not created: error %dn", err);
        err_exit((const char)err, "pthread_create error");
    }
    printf("Thread 1 created. Trying to create Thread 2n");
    if((err = pthread_create (&thread_tempReading,   NULL, task2, NULL))!=0)
    {
    printf("Thread 2 not created: error %dn", err);
        err_exit((const char)err, "pthread_create error");
    }
    printf("Thread 2 created. Trying to create Thread 3n");
    if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
    {
     printf("Thread 3 not created: error %d %dn", err);
         err_exit((const char)err, "pthread_create error");
    }
    printf("Thread 3 createdn");
    /*The main thread must block the SIGALRM but catch SIGINT
    SIGQUIT, SIGTERM, SIgkILL*/
    /*empty the omask set from all signals */
    sigemptyset(&omask);
    /*add the signals to the omask*/
    sigaddset(&omask, SIGINT);
    sigaddset(&omask, SIGQUIT);
    sigaddset(&omask, SIGKILL);
    sigaddset(&omask, SIGTERM);
    /*unblock all signals in omask*/
    pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
    printf("Main thread waiting for signaln");
    /*pause will stop the main thread until any signal not blocked by omask will be received*/
    pause();
    printf("Exit signal received: cancelling threadsn");
    pthread_cancel(thread_motionSensor);
    pthread_cancel(thread_tempReading);
    pthread_cancel(thread_platformPost);
    pthread_join(thread_motionSensor, NULL);
    pthread_join(thread_tempReading,  NULL);
    pthread_join(thread_platformPost, NULL);
    printf("Exiting from main thread and processn");
    exit(0);
}

无论该过程有多少个线程,某些线程都会捕获信号并运行信号处理程序,而其他线程(如果有)(如果有)继续进行其业务。信号已发送到该过程,但是该过程获得信号时的作用取决于该过程和线程如何配置其信号处理程序。

完整的规则非常复杂,我认为可以肯定地说,很少有程序员会完全理解它们,并且通常避免使用信号,除了非常有限的目的。有关更多详细信息,请参见此处。

因此,如果有多线程?

,则仅信号中断线程而不是整个过程

是。信号中断执行的单个线程。至少根据POSIX标准。C标准本身并未指定过程或线程的行为。

如果为多螺纹过程生成信号而不是针对特定线程生成的信号,则该信号将被传递到完全属于该过程的螺纹之一(除非所有线程被所有线程阻止)。<</p>