使用 pthread_kill() 向特定线程发送 SIGINT 会导致整个进程终止

问题描述 投票:0回答:1

我有一个非常大的多线程 C 应用程序(由于这个原因和其他一些原因我无法提供完整的代码)。长话短说,其中有两个线程:线程 1 将

SIGINT
发送到线程 2,而线程 2 在
ppoll()
中等待。代码看起来像这样:

主题 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);
}

...

当线程 1 调用

pthread_kill
时,线程 2 预计会从
ppoll()
中删除并打印
"Got EINTR"
来记录,但由于某种原因整个进程被终止。

我目前知道的其他事情:

  1. 代码在过去按预期工作。从那时起,进行了一些看似无关的更改,以允许应用程序从 Postgres 数据库而不是 Oracle 加载数据(旧实现使用 Pro*C,新实现使用 libpq)。负责处理线程的函数的源代码没有任何改变。

  2. 我检查了哪些线程创建了哪些、正在发送哪些信号(从/到)以及所有这些发生的顺序。但旧版本和新版本之间的所有内容看起来都相同(除了线程 1 将

    SIGING
    发送到线程 2 时新版本停止工作,而旧版本继续工作,线程 2 成功打印
    "Got EINTR"
    到日志。

2.5 我绝对确定线程 1 发送

SIGINT
信号 after 线程 2 重新启动
ppoll()

  1. 我尝试使用

    gdb
    ,并付出巨大的努力能够再次确认正确的线程收到
    SIGINT
    ,但遗憾的是仅此而已。

  2. 我尝试创建一个最小的可重现示例,但尚未想出一个(一切都按预期进行)

我对信号的经验很少(在多线程应用程序中使用它们的经验更少,但事实就是如此),所以我可能没有提供足够的信息,但我并不期待确切的答案 - 只是一些关于如何的想法了解可能导致此问题的原因。如果评论中指出,我将用更具体的信息更新问题。

c pthreads signals
1个回答
0
投票

我认为你只是缺少一个信号处理程序。

信号处置是在“每个进程”的基础上进行的。 SIGINT 的默认信号处理是终止当前进程。这意味着,如果您尚未注册信号处理程序(或完全忽略信号),则默认信号处理将决定发生什么情况。对于 SIGINT,默认是终止进程(因此终止其所有线程)。 如果您至少有一个线程未屏蔽该信号,并且您没有为该信号注册任何处理程序,则您的进程将被终止。如果您想避免这种情况并且希望能够捕获信号,则必须为其注册一个处理程序。

当线程 1 调用 pthread_kill 时,线程 2 应该从 ppoll() 中删除并打印“Got EINTR”来记录,但由于某种原因整个进程被终止。

仅当您注册了信号处理程序时才会出现这种情况。如果没有,由于 SIGINT 的默认配置,您的整个进程将按其应有的方式终止。

我的建议:好好阅读

man 7 signal

,这将消除您可能存在的一些疑虑,并帮助您更好地理解信号的工作原理。

	
© www.soinside.com 2019 - 2024. All rights reserved.