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

调用pthread_kill()向指定线程发送SIGINT导致进程整体终止

多线程C应用SIGINT触发进程意外终止问题

我有一个大型多线程C应用(无法提供完整代码),核心场景是:线程1调用pthread_kill()向线程2发送SIGINT信号,此时线程2正处于ppoll()等待状态。预期线程2退出ppoll()并打印"Got EINTR"后继续运行,但实际进程直接终止。

相关代码

线程1代码

...

if (thread && pthread_kill(&thread, SIGINT) != 0)
{
    fprintf(log1, "Got error: %s", strerror((int)errno));
}

...

注:thread是存储线程2句柄的pthread_t类型变量

线程2代码

...
sigset_t mask;
int rc;

sigemptyset(mask);

...

while(true)
{
    ...
    rc = ppoll(fds, nfds, NULL, mask);
    if (rc < 0)
    {
        if (errno == EINTR) fprintf(log2, "Got EINTR");
        else fprintf(log2, "Got error: %s", strerror((int)errno));
        continue;
    }

    fprintf(log, "%d descriptor(s) ready", rc);
}

...

已知信息

  • 代码此前运行正常,仅将数据加载源从Oracle(Pro*C实现)改为Postgres(libpq实现),线程及信号相关代码未改动
  • 线程创建、信号收发的逻辑和顺序新旧版本完全一致,仅新版本发送SIGINT后进程终止,旧版本线程2正常处理并继续运行
  • 可确认线程1是在线程2进入ppoll()后才发送SIGINT
  • gdb调试确认目标线程收到了SIGINT,但未获取更多有效信息
  • 编写最小复现示例未成功,示例中逻辑正常运行

排查思路

  1. 修正并验证信号掩码的正确性

    • 首先注意线程2中sigemptyset(mask)存在参数错误,sigemptyset的参数应为指针,正确写法是sigemptyset(&mask),错误写法会导致未定义行为,可能是新版本才暴露的问题
    • 在ppoll()调用前,用pthread_sigmask(SIG_BLOCK, NULL, &current_mask)获取线程2的当前信号掩码,打印确认SIGINT未被屏蔽
    • 检查libpq初始化或运行过程中是否全局修改了进程/线程的信号掩码
  2. 检查SIGINT的信号处理函数状态

    • 用sigaction查询当前SIGINT的处理函数,确认是否被libpq改为默认终止行为(SIG_DFL)——默认信号处理是进程级的,若未屏蔽SIGINT,任何线程收到信号都会触发进程终止
    • 在新旧版本中分别对比主线程、线程2的SIGINT处理函数,看是否存在差异
  3. 排查libpq对线程和信号的影响

    • 确认libpq是否创建了额外线程,这些线程是否未屏蔽SIGINT:即使使用pthread_kill指定线程,若目标线程未屏蔽但其他线程也未屏蔽,信号可能被其他线程接收并触发默认处理
    • 查看libpq核心函数(如PQconnectdb、PQexec)是否有修改信号掩码或注册信号处理逻辑的代码,比如为中断连接而修改SIGINT处理
    • 测试仅加载libpq但不建立数据库连接的场景,看问题是否重现,缩小排查范围
  4. 明确进程终止的具体原因

    • 启用核心转储(ulimit -c unlimited),生成core文件后用gdb分析,查看终止时的线程栈回溯,确认是哪个线程触发了进程终止
    • 用gdb运行程序,进程终止时执行info signals查看SIGINT的状态,执行bt full获取详细调用栈信息
    • 检查是否存在SIGINT触发的连锁错误(如内存访问异常)导致进程终止
  5. 验证ppoll调用的有效性

    • 确认ppoll的参数(fds、nfds、mask)是否正确,替换ppoll为poll(配合pthread_sigmask手动屏蔽信号),看问题是否依然存在,排除ppoll本身的调用错误
    • 检查ppoll返回错误时的errno是否真的是EINTR,或者是否有其他错误被忽略后引发异常
  6. 检查线程信号掩码的继承关系

    • 确认线程2创建时是否继承了主线程的信号掩码,新版本中主线程的信号掩码是否因libpq的修改而发生变化
    • 用pthread_attr_getsigmask检查线程创建时的属性,确认信号掩码配置是否符合预期

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 22:50:07