You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 03:16:13