【问题标题】:Is it valid to call pthread_join on the main thread?在主线程上调用 pthread_join 是否有效?
【发布时间】:2010-11-19 18:31:52
【问题描述】:

这段代码的行为是否明确?

#include <stdio.h>
#include <pthread.h>

pthread_t mt;

void *start(void *x)
{
    void *y;
    pthread_join(mt, &y);
    printf("joined main thread\n");
    return 0;
}

int main()
{
    pthread_t t;
    mt = pthread_self();
    pthread_create(&t, 0, start, 0);
    pthread_exit(0);
}

【问题讨论】:

    标签: c pthreads posix


    【解决方案1】:

    是的,这是可能的。事实上,这种可能性是pthread_detach() 存在的主要原因之一。来自pthread_detach() 的 POSIX 文档(请参阅man pthread_detach):

       It  has  been suggested that a "detach" function is not necessary; the
       detachstate thread creation attribute is sufficient,  since  a  thread
       need  never  be dynamically detached. However, need arises in at least
       two cases:
    
        1. In a cancellation handler for a pthread_join() it is nearly essen-
           tial  to  have  a pthread_detach() function in order to detach the
           thread on which pthread_join() was waiting. Without it,  it  would
           be  necessary  to  have  the  handler do another pthread_join() to
           attempt to detach the thread, which would both delay the cancella-
           tion  processing  for an unbounded period and introduce a new call
           to pthread_join(), which might itself need a cancellation handler.
           A dynamic detach is nearly essential in this case.
    
    
        2. In  order  to  detach the "initial thread" (as may be desirable in
           processes that set up server threads).
    

    所以根据标准,您提出的建议是可以的。

    编辑:为了进一步确认,POSIX description of exec() 声明:

    新进程中的初始线程 图像应该是可连接的,就像创建的一样 将 detachstate 属性设置为 PTHREAD_CREATE_JOINABLE。

    【讨论】:

    【解决方案2】:

    我无法想象你为什么要在现实世界的应用程序中这样做(如果你能想到一个例子,请有人评论一个例子),但我不相信这是可能的。我查看的所有关于 pthread 的搜索总是从主线程调用连接,而不是从辅助线程。

    连接还要求您尝试连接的线程是使用 PTHREAD_CREATE_JOINABLE 标志创建的。我找不到任何说明主线程是否是这样创建的文档。

    Codeguru 有一个类似的问题 here 可能会或可能不会帮助解决它。

    如果您想要完成的是子线程在主线程退出后继续,您应该创建分离的子线程,或者使用fork/vfork,具体取决于您所在的平台。

    【讨论】:

    • PTHREAD_CREATE_JOINABLE 是根据 POSIX 的默认值;你不需要使用pthread_attr_t 来获取它。
    • 顺便说一句,我同意这可能不是一个好习惯。我从实现是否必须支持这种可疑用法的角度提出问题,而不是应用程序编写者是否应该使用它。 :-)
    【解决方案3】:

    您的方法对我来说看起来正式有效,特别是因为您在 main 末尾执行 pthread_exit

    另一方面,我在 POSIX 中没有找到任何迹象表明 main 的初始线程是否应该是可连接的。 psmears 回答中的基本原理只要求main 应该是可拆卸的,因为它被创建为可连接的。

    此外,其他恶意软件可能会从 main 调用的子例程中调用 pthread_detach。所以你应该明确检查pthread_join的返回值来检查这种情况。

    此外,在您的示例代码中,您在 start 的创建和 main 的终止之间存在竞争:

    • main 可能在 start 到达 pthread_join 之前终止

    mt 变量的访问进行互斥应该可以解决这个问题。

    【讨论】:

    • 如果pthread_detach已经在一个线程上被调用,那么在那个线程上调用pthread_join的结果是未定义的;它不需要返回任何错误,事实上,如果线程已经终止并且它的资源被释放,它可能会崩溃。
    • 假设主线程是可连接的,如果mainstart调用pthread_join之前调用pthread_exit是没有问题的。可连接线程的语义类似于子进程的pid。就像pid 被保留(僵尸进程)直到你等待它并收集它的退出状态,pthread_t 在你分离或加入线程之前是有效的,即使它已经退出了。
    • 我不同意你的第一句话。不可连接的线程是可检测的,不会导致未定义的结果。 The pthread_join() function shall fail if: *EINVAL* The implementation has detected that the value specified by thread does not refer to a joinable thread.
    • R.是正确的。标准的措辞令人困惑——但它说pthread_join() 将失败如果实现检测到无效的线程ID。它没有说实现必须能够检测到这样一个无效的线程 id,实际上 Linux 上的 glibc 可以并且将会在这些情况下崩溃:参见 udrepper.livejournal.com/tag/programming%20posix
    • POSIX 2008 更清楚地说明了这一点,并将所有那些针对不可检测条件(其中许多涉及未初始化变量的值)的虚假 shall fail 语句更改为 可能失败。期望pthread_join 在分离的线程如果它仍在运行 上返回EINVAL 并不是那么不合理(尽管 POSIX 2008 使它成为 UB),但是如果线程已经终止,你应该期待所有地狱挣脱。 SIGSEGV 如果你很幸运,并且如果线程 id 被重新分配或内存被重新分配给其他东西,则随机加入或破坏不同的线程。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-27
    • 1970-01-01
    • 2018-04-13
    • 2020-03-02
    相关资源
    最近更新 更多