简介
首先,每个线程都有自己的掩码,指定它正在侦听的信号。创建线程时,它会继承创建它的线程的掩码(让我称之为父线程),当调用pthread_create 时它是活动的。
一般来说,如果一个线程正在监听信号,那么其他线程不应该监听信号会更好,除非您希望有多个线程执行相同的操作(例如,在服务器中处理连接请求以同时处理多个请求时) )。通过这种方式,您始终知道哪个线程正在处理信号。否则你不知道哪个线程正在接收信号以及程序的哪个部分正在执行:调试变得不可能(一个例子是你自己的问题)。
要更改从父线程创建的子线程的掩码,您可以创建一个新掩码,请将其设置为活动状态,使用pthread_create 创建一个新线程,然后在父线程中再次激活之前的掩码(参见答案末尾的代码)。
编辑:根据this post,最好使用sigaction() 而不是signal。在现代系统中signal() 是用sigaction() 实现的,所以应该没有任何区别。但是,如果使用它的旧实现,可能会出现问题。
回答
因此,如果有信号,则仅中断线程而不是整个进程
是多线程吗?
NO:信号只是信号,它们不做任何事情。与信号相关的动作有能力做一些事情,包括停止程序或终止线程。每个信号都有一个关联的默认操作,SIGINT 的默认操作是中断进程。
使用您的处理程序,您将覆盖默认操作。因此它不会再停止程序,但会执行您在线程函数中指定的操作。
在第一种情况下,您只有一个线程,即主线程,这是一个无限循环,只要他还活着,它就会始终捕获信号,这就是行为的原因。如果您重新发送信号,则信号会暂时被阻塞,直到信号处理程序结束执行。然而,如果在处理程序执行时发送了许多信号,您可能会丢失一些信号。
事实上,正如here 所解释的那样,阻塞信号被设置为待处理,但没有排队。术语 pending 意味着操作系统通过设置一个标志来记住有一个信号等待在下一个机会被传递,而 not queued 意味着它通过在某处设置标志,但不是通过准确记录到达的信号数量。
因此,如果信号被发送一次、5 次或更多(尝试在您的程序中多次按 CTRL+C:我已经尝试过),而信号处理程序正在执行它会产生完全相同的行为。
在第二种情况下,您有 3 个线程:main 一个、t1 和 t2:它们都可以看到信号 SIGINT,并且它们都关联了相同的信号处理程序。如果您一个接一个地按 3 次,它们三个都将执行处理程序:这就是您看不到任何延迟的原因。如果您按非常非常快并且超过 3 次(侦听该信号的线程数),我认为您会看到类似于第一个行为的内容。
我将以the code I posted in a question 结束我的回答,我在其中设置了掩码,以便某些信号仅被主线程捕获:
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDs\n");
...
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINT HANDLER\n");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threads\n");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2\n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3\n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 created\n");
/*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 signal\n");
/*pause will stop the main thread until any signal not blocked by omask will be received*/
pause();
printf("Exit signal received: cancelling threads\n");
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 process\n");
exit(0);
}