//线程共享信号处理方式
//线程独享各自的阻塞信号集
//测试结果
/*
* 主线程 分线程 同时设置屏蔽字 发送信号 并没有被捕捉 =>正常
* 主线程 分线程 都没有设置屏蔽字 发送信号 主线程优先捕捉了信号一次
* 主线程 先设置屏蔽字再创建分线程 分线程没有主动设置 发送信号 依然没有被捕捉=>但是因为主线程在设置屏蔽后才创建的分线程,分线程继承了主线程的屏蔽字,所以分线程虽然没有主动去设置屏蔽,但是其阻塞信号集里面依然是屏蔽的
* 主线程 先创建分线程再设置屏蔽字 分线程 没有设置屏蔽 发送信号 被分线程捕捉了一次
* 主线程 没有设置屏蔽 分线程设置屏蔽 发送信号 被主线程捕捉了一次
*/
/*
*
POSIX标准对多线程情况下的信号机制提出了一些要求:
信号处理函数必须在多线程进程的所有线程之间共享, 但是每个线程要有自己的挂起信号集合和阻塞信号掩码。
POSIX函数kill / sigqueue必须面向进程, 而不是进程下的某个特定的线程。
每个发给多线程应用的信号仅递送给一个线程, 这个线程是由内核从不会阻塞该信号的线程中随意选出来的。
如果发送一个致命信号到多线程, 那么内核将杀死该应用的所有线程, 而不仅仅是接收信号的那个线程。
结论:
1.sigaction注册时机
sigaction不论在主线程中注册还是在子线程中注册,最终进程内的所有线程都调用sigaction注册的回调函数来处理。
sigaction注册不同信号,则不同信号对应着sigaction注册时的回调函数
sigaction注册相同信号,相同信号被注册多个回调函数,此时信号发来,执行的是最新的一个回调函数,等又有一个sigaction注册了之前的信号,则之前信号的回调函数会被更新会新的回调函数
2.哪个线程处理信号
如果主线程不阻塞某个信号,则优先处理信号的线程是主线程,且一个信号只会被一个线程所处理
当主线程阻塞了某个信号,则交由子线程处理,通过多次测试得出,优先处理信号的线程是pthread_ID较大的那个
虽然每个线程都有自己独立的signal mask,但是要注意子线程的mask是会从主线程继承而来的,如果主线程先阻塞了某个信号,再创建子线程,而子线程没有设置自己的signal mask ,则子线程也默认阻塞了该信号
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
void PrintundoSignal(const char* str)
{
printf(str);
sigset_t set;
sigemptyset(&set);
sigpending(&set);
for (int i = 1; i < 32; ++i)
{
printf("signal%d state:%d\n", i, sigismember(&set, i));
}
}
void Catch(int signo)
{
pthread_t pid = pthread_self();
printf("%d signal is catched\n", signo);
// PrintundoSignal("Catch");
}
void* thread(void*)
{
//设置线程的阻塞信号集
printf(" this is thread \n");
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
//将set信号集添加到信号阻塞集中
// sigprocmask(SIG_BLOCK, &set, NULL);
PrintundoSignal("sign:thread");
while (1)
{
sleep(1);
printf("I am thread\n");
}
return nullptr;
}
int main(void)
{
int ret;
struct sigaction act;
struct sigaction old;
//设置结构体的参数
act.sa_handler = Catch;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGQUIT);
act.sa_flags = 0; //默认属性,信号捕捉函数执行期间,自动屏蔽本信号
//注册捕捉函数
ret = sigaction(SIGUSR1, &act, &old);
if (ret < 0)
{
perror("sigaction error");
exit(1);
}
//设置线程的阻塞信号集
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGUSR1);
// sigprocmask(SIG_BLOCK, &set, NULL);//此处设置再创建线程,分线程会继承主线程的阻塞信号集
pthread_t tid;
printf("main thread.\n");
int rc = pthread_create(&tid, NULL, thread, 0);
//将set信号集添加到信号阻塞集中
sigprocmask(SIG_BLOCK, &set, NULL);
PrintundoSignal("sign:main");
pthread_exit(0);
while (1);
return 0;
}
Linux多线程环境下信号处理机制
最新推荐文章于 2024-07-24 09:58:58 发布