【问题标题】:Can I use pthread_join() to check for terminated thread?我可以使用 pthread_join() 检查终止的线程吗?
【发布时间】:2015-06-02 22:28:07
【问题描述】:

我需要知道某个线程是否已经终止(如果没有,我必须等待它)。
如果我在终止的线程上调用pthread_join(),它总是在我的 glibc 版本中返回成功。 但是pthread_join() 的文档说如果线程已经终止,它必须返回带有代码ESRCH 的错误。
如果我调用pthread_kill(thread_id, 0),它会返回错误代码ESRCH(如预期的那样)。
在 glibc 源代码中,我看到在 pthread_join() 中可以简单地检查有效的 thread_id,但不能真正检查线程是否存在。 在pthread_kill() 内部有真正的检查(在某些内核列表中)。 有我的测试程序:

#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void * thread_func(void *arg)
{
    printf("Hello! I`m thread_func!\nGood-bye!\n");
    return NULL;
}

int main(void)
{
    int res;
    pthread_t thread_id;

    printf("Hello from main()!\n");
    pthread_create(&thread_id, NULL, thread_func, NULL);
    printf("Waiting...\n");
    sleep(3);

    res = pthread_join(thread_id, NULL);
    printf("pthread_join() returned %d (%s)\n", res, strerror(res));

    res = pthread_kill(thread_id, 0);
    printf("pthread_kill() returned %d (%s)\n", res, strerror(res));

    return 0;
}

它的输出:

你好! 等待... 你好!我是线程函数! 再见! pthread_join() 返回 0(成功) pthread_kill() 返回 3(没有这样的进程)

我的问题:使用 pthread_join() 检查终止的线程是否安全,或者我必须始终使用 pthread_kill()?

【问题讨论】:

    标签: pthreads


    【解决方案1】:

    当一个线程退出时,它的代码会停止运行,但它的“尸体”会留在周围,以便父级收集返回代码。(1)支持>

    因此,即使您认为该线程已完全消失,但事实并非如此。

    pthread_join 的调用将检查所述尸体的返回码,以便通知父母事情的结果。 收集完之后,线程就可以真正的休息了。(2)

    这就是为什么pthread_join() 会返回成功代码而pthread_kill 不会 - 你不能杀死已经死掉的线程,但你允许加入一个已经死了但仍然温暖的人:-)

    您可能会通过尝试以下代码获得更好的教育,该代码尝试加入线程两次:

    #include <errno.h>
    #include <pthread.h>
    #include <signal.h>
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
    
    void * thread_func(void *arg) {
        printf("Hello! I`m thread_func!\nGood-bye!\n");
        return NULL;
    }
    
    int main(void) {
        int res;
        pthread_t thread_id;
    
        printf("Hello from main()!\n");
        pthread_create(&thread_id, NULL, thread_func, NULL);
        printf("Waiting...\n");
        sleep(3);
    
        res = pthread_join(thread_id, NULL);
        printf("pthread_join() returned %d (%s)\n", res, strerror(errno));
    
        res = pthread_join(thread_id, NULL);
        printf("pthread_join() returned %d (%s)\n", res, strerror(errno));
    
        return 0;
    }
    

    在我的系统上,我看到:

    Hello from main()!
    Waiting...
    Hello! I`m thread_func!
    Good-bye!
    pthread_join() returned 0 (No error)
    pthread_join() returned 3 (No error)
    

    换句话说,虽然线程已经死了,但第一个pthread_join() 可以工作。


    (1) 如果您愿意,您可以pthread_detach 一个线程,以便在终止时立即释放其资源。那将是:

    pthread_create(&thread_id, NULL, thread_func, NULL);
    pthread_detach(thread_id);
    

    但我很确定在这种情况下,即使线程仍然存在,连接也会失败。

    要查看线程是否仍在运行无论它是否已分离,您可以使用:

    if (pthread_kill(thread_id, 0) != 0)
        // Thread is gone.
    

    (2) 为这个答案的病态语气道歉,我今天感觉有点阴暗:-)

    【讨论】:

    • 感谢您的回答,但我的 man 3 pthread_join 说:“加入之前已加入的线程会导致未定义的行为。”。
    • @Zhenya4880,我并不是说你应该在生产代码中这样做,这是一个说明,表明在你收获返回码之前线程不会完全消失。如果您想从第一次连接中得到错误,请在创建线程时分离线程 - 我将添加更多代码。
    • 这个if (pthread_kill(thread_id, 0) != 0) // Thread is gone. 并不总是正确的。 pthread_kill() 可能不会返回错误并且可能会发送信号,但它可能不会杀死线程。请参阅stackoverflow.com/questions/223644/… 了解更多信息。
    • @Piotr,它真正起作用。 0 的信号比较特殊,表示应该进行错误检查(包括检查线程是否存在),但实际上没有发送任何信号。 并不是要杀死线程,只是表明线程在那里。根据 Open Group 文档 (pubs.opengroup.org/onlinepubs/009695399/functions/…),如果信号编号错误,pthread_kill 将返回 EINVAL(因为0 是有效的,所以在这种情况下不是这样),如果线程没有,则返回 ESRCH不存在。没有其他可能发生。因此,如果返回码不为零,则线程已消失。
    【解决方案2】:

    pthread_join 结束线程对资源的使用。当线程到达终点并准备好被清理时,它返回 0。默认情况下,线程不会自行“消失”。

    归零意味着:

    1. the thread got cleaned up
    2. the thread WAS still there waiting
    

    所以不,不要使用 pthread_kill,你有一个错误的主要假设:线程,除非设置为不可连接,否则在线程返回时不退出并清理堆栈和内存资源。换句话说,return NULL 在您的示例中不会终止线程。 pthread_join 做到了。

    所以,是的,使用 pthread_join 来等待线程完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多