Pthread中的信号处理:如何接收pthread_kill发送的信号?
多线程中用pthread_kill发送信号的接收方法
在多线程场景下,用pthread_kill给指定线程发信号的接收逻辑,核心围绕信号的进程级特性+线程信号掩码来控制,以下是具体实现方式和注意点:
1. 先明确信号的默认行为
默认情况下,进程内所有线程共享同一个信号处理函数(通过signal()或sigaction()注册),但信号会被操作系统随机分配给一个未屏蔽该信号的线程。如果要指定线程接收信号,必须通过线程信号掩码来做限制。
2. 绑定指定线程接收信号的步骤
步骤一:注册信号处理函数(可选,同步等待方式无需此步骤)
推荐用sigaction()替代signal(),前者更安全且支持更多配置:
#include <signal.h> void sig_handler(int sig) { // 仅能调用异步安全函数,比如write(),禁止使用printf()、malloc()这类非异步安全接口 write(STDOUT_FILENO, "收到信号\n", 8); } // 在进程初始化阶段注册 struct sigaction sa; sa.sa_handler = sig_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGUSR1, &sa, NULL);
步骤二:设置线程信号掩码,锁定接收线程
用pthread_sigmask()给除目标线程外的所有线程屏蔽目标信号,只留目标线程可接收:
#include <pthread.h> #include <signal.h> // 定义要发送的信号集合 sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); // 在主线程或所有非目标线程中调用,屏蔽SIGUSR1 pthread_sigmask(SIG_BLOCK, &mask, NULL); // 在目标线程中调用,解除SIGUSR1的屏蔽(若之前被全局屏蔽过) pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
此时调用pthread_kill(target_thread, SIGUSR1),信号只会被目标线程接收。
3. 两种信号接收方式
方式一:异步触发信号处理函数
只要目标线程未屏蔽信号,信号会触发之前注册的处理函数,且在目标线程的上下文执行。需严格遵守异步安全规则,避免调用非线程安全、非异步安全的函数。
方式二:同步等待信号(更可控)
若不想用异步处理函数,可让目标线程主动调用sigwait()或sigwaitinfo()阻塞等待信号,这种方式在正常线程上下文处理,无异步安全限制:
// 目标线程的执行函数 void* target_thread_func(void* arg) { sigset_t wait_mask; sigemptyset(&wait_mask); sigaddset(&wait_mask, SIGUSR1); int received_sig; // 阻塞等待信号 sigwait(&wait_mask, &received_sig); if (received_sig == SIGUSR1) { // 此处可正常调用任意函数,比如printf、malloc等 printf("目标线程收到SIGUSR1信号\n"); } return NULL; }
4. 关键注意事项
pthread_kill的第二个参数传0时,不会发送实际信号,仅用于检查目标线程是否存在。- 不要给线程发送SIGKILL、SIGSTOP这类无法捕获/忽略的信号,否则整个进程会直接终止。
- 若不设置线程信号掩码,信号会被随机分配给一个未屏蔽的线程,无法保证指定线程接收。
内容的提问来源于stack exchange,提问作者Apabila X Terkadang
相关产品推荐
相关产品推荐

