用户态 kill 与 pthread_kill 的区别?

发布于:2025-09-04 ⋅ 阅读:(18) ⋅ 点赞:(0)

在 Linux 用户态中,pthread_killkill 都能发送系统信号,但它们的作用对象、使用场景和行为有显著区别,核心差异在于信号的接收者不同

1. 作用对象不同

  • kill(pid_t pid, int sig)
    用于向 进程 发送信号,pid 参数指定目标进程的 ID:
    • pid > 0:向 ID 为 pid进程发送信号
    • pid = 0:向当前进程所在进程组的所有进程发送信号
    • pid = -1:向系统中所有有权限发送的进程发送信号(特殊权限下)
    • pid < -1:向进程组 ID 为 |pid| 的所有进程发送信号
  • pthread_kill(pthread_t thread, int sig)
    用于向 同一进程内的特定 线程 发送信号,thread 参数是目标线程的 ID(由 pthread_create 返回)。

2. 信号的处理范围不同

  • kill 发送的信号:属于进程级信号,默认由进程内的 “主线程” 或 “任意线程” 处理(取决于信号处理函数的注册方式)。
    例如,若进程中注册了 SIGINT 的处理函数,用 kill 向该进程发送 SIGINT,会触发进程内的该处理函数(由内核选择一个线程执行)。
  • pthread_kill 发送的信号:属于线程级信号,专门针对指定线程,信号处理函数在目标线程的上下文中执行。
    例如,向 ‘线程 A’ 发送 SIGUSR1,若该信号已注册处理函数,则处理函数在 ‘线程 A’ 中运行。

3. 特殊信号的行为差异

  • 对于会导致进程终止的信号(如 SIGKILLSIGTERM):
    • 无论用 kill 还是 pthread_kill 发送,最终都会导致整个进程终止(因为线程是进程的一部分,进程终止会带动所有线程终止)。
    • 区别在于:kill 直接针对进程,pthread_kill 虽指定线程,但信号的 “终止进程” 语义会作用于整个进程。
  • 对于可捕获的信号(如 SIGUSR1SIGALRM):
    • kill 发送的信号可能被进程内任意线程捕获(内核调度决定)。
    • pthread_kill 发送的信号只会被目标线程捕获(如果该线程未阻塞此信号)。

4. 使用场景不同

  • kill 的典型场景
    进程间通信,例如:
    • 终端通过 kill 向后台进程发送 SIGTERM 要求其退出
    • 父进程向子进程发送信号控制其行为
  • pthread_kill 的典型场景
    同一进程内的线程间通信,例如:
    • 主线程向阻塞的子线程发送信号,中断其阻塞状态(如从 sleepwait 中唤醒)
    • 通知特定线程处理某个事件

示例对比

#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>

// 信号处理函数
void sig_handler(int sig) {
    printf("信号 %d 在线程 %lu 中被处理\n", sig, pthread_self());
}

// 子线程函数
void *thread_son_func(void *arg) {
    printf("子线程 %lu 启动\n", pthread_self()); //与ps -T -p <PID>得到的线程ID无关,这样打印也不太规范
    while (1) {
        sleep(1); // 模拟阻塞
    }
    return NULL;
}

int main() {
    signal(SIGUSR1, sig_handler); // 注册信号处理函数
    pthread_t tid;
    pthread_create(&tid, NULL, thread_son_func, NULL);

    sleep(1); //给线程创建留点时间
    // 用 pthread_kill 向 "子线程" 发送信号
    pthread_kill(tid, SIGUSR1); // 信号在子线程中处理

    sleep(1); //给信号中打印留点时间
    // 用 kill 向当前 "进程" 发送信号(可能被任意线程处理)
    kill(getpid(), SIGUSR1); // 信号可能在主线程或子线程中处理

    pthread_join(tid, NULL);
    return 0;
}

输出可能为:

子线程 140610751647488 启动
信号 10 在线程 140610751647488 中被处理  // pthread_kill 发送,子线程处理
信号 10 在线程 140610759944576 中被处理  // kill 发送,主线程处理(可能不同)

总结

特性 kill pthread_kill
接收者 进程(或进程组) 同一进程内的特定线程
信号处理上下文 进程内任意线程(内核决定) 目标线程本身
主要用途 进程间信号通信 同一进程内线程间信号通信
对进程的影响 可能终止整个进程(如 SIGKILL 同左(信号语义决定,与线程无关)

简单说:kill 是 “给进程发信号”,pthread_kill 是 “给进程内的某个线程发信号”。