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

使用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;
    }
}

修复说明

  1. 跨进程信号传递:父进程通过kill(pid, SIGUSR1)给子进程发信号,子进程的线程负责处理,避免了无效的线程ID跨进程使用。
  2. 子进程存活保持:子进程调用pthread_join等待线程,确保子进程不会提前退出,线程能持续运行接收信号。
  3. 信号处理优化:全局设置一次信号处理函数,线程中用pause()挂起等待信号,减少CPU占用。
  4. 随机数种子初始化:将srand移到循环外,确保随机数序列正常生成。

内容的提问来源于stack exchange,提问作者Bryan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 12:25:21