用户态 kill 与 pthread_kill 的区别?
在 Linux 用户态中,pthread_kill
和 kill
都能发送系统信号,但它们的作用对象、使用场景和行为有显著区别,核心差异在于信号的接收者不同:
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. 特殊信号的行为差异
- 对于会导致进程终止的信号(如
SIGKILL
、SIGTERM
):- 无论用
kill
还是pthread_kill
发送,最终都会导致整个进程终止(因为线程是进程的一部分,进程终止会带动所有线程终止)。 - 区别在于:
kill
直接针对进程,pthread_kill
虽指定线程,但信号的 “终止进程” 语义会作用于整个进程。
- 无论用
- 对于可捕获的信号(如
SIGUSR1
、SIGALRM
):kill
发送的信号可能被进程内任意线程捕获(内核调度决定)。pthread_kill
发送的信号只会被目标线程捕获(如果该线程未阻塞此信号)。
4. 使用场景不同
kill
的典型场景:
进程间通信,例如:- 终端通过
kill
向后台进程发送SIGTERM
要求其退出 - 父进程向子进程发送信号控制其行为
- 终端通过
pthread_kill
的典型场景:
同一进程内的线程间通信,例如:- 主线程向阻塞的子线程发送信号,中断其阻塞状态(如从
sleep
或wait
中唤醒) - 通知特定线程处理某个事件
- 主线程向阻塞的子线程发送信号,中断其阻塞状态(如从
示例对比
#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
是 “给进程内的某个线程发信号”。