使用pthread_kill()向线程发送SIGUSR1时出现段错误求助
问题分析与修复方案
你的代码存在几个关键错误,导致要么线程收不到信号,要么出现段错误:
核心错误:跨进程使用线程ID
fork() 后父子进程拥有完全独立的地址空间,子进程中创建的 reporter_thread 线程ID在父进程中是无效的。父进程调用 pthread_kill(reporter_thread, SIGUSR1) 时,会尝试访问不属于自己进程的线程资源,直接触发段错误。
其他关键问题
- 子进程提前退出:子进程创建线程后没有等待线程运行,直接终止,导致线程被强制销毁,根本无法接收信号。
- 父进程等待时机错误:父进程调用
wait(NULL)会阻塞直到子进程结束,之后才开始发信号,这时候子进程已经不存在,信号完全无意义。 - 不必要的重复设置信号处理:
reporter线程里循环调用sigaction(SIGUSR1, &sa, NULL)完全多余,信号处理函数只需设置一次。 - 随机数生成问题:把
srand((unsigned)time(NULL))放在循环里,由于sleep(2)后时间可能未变化,会导致生成重复的随机数。
修复后的代码
我们调整架构,让子进程负责持续运行线程接收信号,父进程负责定时发送信号(用kill()给子进程发信号,再让子进程的线程处理):
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <pthread.h> #include <sys/types.h> #include <sys/wait.h> #include <time.h> sigset_t new_sig_set; // 信号掩码 void handle_SIGUSR1(int sig) { write(STDOUT_FILENO, "SIGUSR1 received\n", 18); } void *reporter(void *arg) { printf("Entered reporter thread\n"); // 解除当前线程的SIGUSR1阻塞 pthread_sigmask(SIG_UNBLOCK, &new_sig_set, NULL); // 线程保持运行,等待信号 while(1) { pause(); // 挂起等待信号,比空循环更高效 } return NULL; } int main(int argc, char **argv) { // 初始化信号掩码,添加SIGUSR1 sigemptyset(&new_sig_set); sigaddset(&new_sig_set, SIGUSR1); // 主线程阻塞SIGUSR1,让子线程去处理 pthread_sigmask(SIG_BLOCK, &new_sig_set, NULL); // 设置信号处理函数(进程全局有效) struct sigaction sa; sa.sa_handler = handle_SIGUSR1; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); // 必须初始化sa_mask,否则会有未定义行为 sigaction(SIGUSR1, &sa, NULL); srand((unsigned)time(NULL)); // 只初始化一次随机数种子 int pid = fork(); if (pid == 0) { pthread_t reporter_thread; pthread_create(&reporter_thread, NULL, reporter, NULL); printf("Created reporter thread in child process (PID: %d)\n", getpid()); // 子进程等待线程结束(这里线程是死循环,实际会一直运行) pthread_join(reporter_thread, NULL); exit(0); } else { printf("Parent process sending signals to child (PID: %d)\n", pid); while (1) { printf("Generating signal\n"); // 生成1-2的随机数 int random = rand() % 2 + 1; if (random == 1) { printf("Sending signal: SIGUSR1\n"); kill(pid, SIGUSR1); // 给子进程发信号 } else { printf("Something else\n"); } sleep(2); } // 实际不会走到这里,如需优雅退出可添加信号处理终止子进程 wait(NULL); return 0; } }
修复说明
- 跨进程信号传递:父进程通过
kill(pid, SIGUSR1)给子进程发信号,子进程的线程负责处理,避免了无效的线程ID跨进程使用。 - 子进程存活保持:子进程调用
pthread_join等待线程,确保子进程不会提前退出,线程能持续运行接收信号。 - 信号处理优化:全局设置一次信号处理函数,线程中用
pause()挂起等待信号,减少CPU占用。 - 随机数种子初始化:将
srand移到循环外,确保随机数序列正常生成。
内容的提问来源于stack exchange,提问作者Bryan
相关产品推荐
相关产品推荐

