【问题标题】:Why child threads alive after the main threads are killed?为什么在主线程被杀死后子线程还活着?
【发布时间】:2016-08-03 08:46:20
【问题描述】:

我编写了一个代码,我从父线程创建了两个子线程。

然后,在这些子线程中接收到来自另一个终端的信号后,我打印了threadID 并退出了线程。

我有 2 个问题。

  1. 我正在接收来自子线程的信号。为什么打印父线程的threadID

  2. 杀死父线程后,子线程怎么可能还活着??

代码:

void sig_handler(int signo)
{
    if (signo == 1){
        printf("%d\n", pthread_self());
        pthread_exit(NULL);
    }
}

void* doSomeThing(void* arg)
{
    printf("In function -> %d\n", pthread_self());
    if (signal(1, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGHUP\n");
    while(1)
        sleep(1);
    return NULL;
}

int main(int argc, char *argv[])
{
    printf("In function -> %d\n", pthread_self());
    char *ch1;
    pthread_t tid1, tid2;
    ch1 = "random";
    int ret1, ret2;

    ret1 = pthread_create(&tid1, NULL, &doSomeThing, (void *) ch1 );
    ret2 = pthread_create(&tid2, NULL, &doSomeThing, (void *) ch1 );

    while(1)
        sleep(1);
    return 0;
}

这是终端中给出的输出图像:

前 3 行是 3 个threadIDs。第一个是主线程threadIDs,然后是两个辅助线程。

然后从下面的代码块中打印出threadIDs。

if (signo == 1){
    printf("%d\n", pthread_self());
    pthread_exit(NULL);
}

为什么会这样???

【问题讨论】:

  • signal 不适用于线程。
  • 这是否意味着pthread_self() 函数没有给出正确的threadID ?在收到signal ?? 后调用
  • @JishnuBanerjee pthread_self() 将给出调用线程的线程 ID。但真正的问题是不可能有每个线程的信号处理程序。信号处理是全过程的。请参阅链接的手册页中有关如何阻止信号的示例。
  • C 标准说:“在多线程程序中使用这个函数 [signal] 会导致未定义的行为。”

标签: c linux multithreading pthreads signals


【解决方案1】:

信号传递给进程,而不是单个线程。因此,您不能像在这里那样只为一个线程使用信号处理程序。 您可以做的是使用pthread_sigmask() 阻止您感兴趣的信号,并让专用线程使用sigwait() 处理信号,这是最常见的方式。

【讨论】:

  • 这里究竟是如何调用 sig_handler() 的?我的意思是每次调用 sig_handler() 时,OP 都会获得一个不同的线程 ID,即 OP 发送了一个信号。这个特定程序实际上是如何管理/针对这些信号采取行动的?
  • OP 发送的信号不是特定于线程的。它是整个过程的。因此,您无法确定/知道信号传递到哪个线程。 pthreads(7) 说:“POSIX.1 区分了定向到整个进程的信号和定向到单个线程的信号的概念。根据 POSIX.1,进程定向信号(发送 kill(2),例如)应该由进程中的一个任意选择的线程来处理。” “任意信号传递”意味着任何线程都可以接收信号并调用信号处理程序并打印其 threadID。
【解决方案2】:

此外,您只能从信号处理程序中安全地调用异步信号安全函数。来自the Linux signal man page

异步信号安全函数

信号处理函数必须非常小心,因为处理 其他地方可能会在执行中的某个任意点被中断 的程序。 POSIX 有“安全功能”的概念。如果一个 信号中断不安全函数的执行,处理程序 要么调用一个不安全的函数,要么 handler 通过调用来终止 longjmp()siglongjmp() 并且程序随后调用 unsafe 函数,则程序的行为未定义。

链接的手册页有一个函数列表,可以安全地从信号处理程序中调用。如果该函数不在该列表中,则调用它是不安全的。没有例外。

请注意,printf()pthread_exit() 均不在异步信号安全函数列表中。

从信号处理程序中调用pthread_exit() 会产生其他几个问题:

  • 退出的线程一般不受任何控制。在许多情况下,信号可以传递到任何线程。

  • 退出线程可能会使对象处于未知状态 - 例如,互斥锁可能被不再存在的线程锁定。

  • 任何线程清理处理程序registered with pthread_cleanup_push() 也将从信号处理程序上下文中调用。

【讨论】:

    猜你喜欢
    • 2022-10-16
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    相关资源
    最近更新 更多