C 在主线程上调用pthread_join是否有效?

C 在主线程上调用pthread_join是否有效?,c,pthreads,posix,C,Pthreads,Posix,此代码的行为是否定义良好 #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_sel

此代码的行为是否定义良好

#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);
}
#包括
#包括
pthread_t mt;
void*start(void*x)
{
void*y;
pthread_join(mt和y);
printf(“连接的主螺纹”);
返回0;
}
int main()
{
pthread_t;
mt=pthread_self();
pthread_创建(&t,0,start,0);
pthread_退出(0);
}

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

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

Codeguru对此也提出了类似的问题,这可能有助于澄清问题,也可能没有帮助澄清问题


如果您希望在主线程退出后继续子线程,则应创建分离的子线程,或者使用
fork
/
vfork
,具体取决于您所处的平台。

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

因此,根据标准,你的建议是好的

编辑:只是为了进一步确认以下内容:

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


我认为您的方法在形式上是有效的,特别是因为您正在执行
main
末尾的
pthread\u exit

另一方面,我在POSIX中没有发现任何迹象表明
main
的初始线程是否应该是可连接的。psmears回答中的基本原理只是要求
main
应该是可分离的,从哪里创建它就可以连接

另外,其他恶意程序可能会从main或so调用的子例程调用
pthread\u detach
。因此,您应该明确地检查
pthread\u join
的返回值以检查这种情况

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

  • main
    可能在
    start
    到达
    pthread\u join

禁用对
mt
变量的访问应该可以确保这一点。

PTHREAD\u CREATE\u JOINABLE
是POSIX的默认值;您不需要使用
pthread\u attr\t
来获得它。顺便说一句,我同意这可能不是一个好的做法。我从实现是否必须支持这种可疑用法的角度提出了这个问题,而不是应用程序编写器是否应该使用它。:-)如果已在线程上调用了
pthread\u detach
,则在该线程上调用
pthread\u join
的结果未定义;它不需要返回任何错误,事实上,如果线程已经终止并且其资源被释放,它可能会崩溃。假设主线程是可连接的,那么如果
main
start
调用
pthread\u join
之前调用
pthread\u exit
就没有问题。可接合线程的语义类似于子进程的
pid
。就像
pid
在您等待并收集其退出状态之前是保留的(僵尸进程),
pthread\u t
在您分离或加入线程之前是有效的,即使它已经退出。我不同意您的第一句话。不可连接的线程是可检测的,不会导致未定义的结果
pthread_join()函数将在以下情况下失败:*EINVAL*实现检测到线程指定的值未引用可连接线程。
R.正确。该标准的措辞令人困惑,但它说如果实现检测到无效的线程id,那么
pthread\u join()
将失败。它没有说实现必须能够检测到这样一个无效的线程id,事实上,Linux上的glibc在这些情况下可能会崩溃:参见POSIX 2008,这一点更加明确,并将所有那些针对不可检测条件(其中许多涉及未初始化变量的值)的伪应失败语句更改为可能失败。期望
pthread_join
在分离的线程上返回
EINVAL
(如果该线程仍在运行),这并不是不合理的(尽管POSIX 2008将其设置为UB),但是如果该线程已终止,您应该期望一切都会失控<代码> SigSeGv如果幸运的话,如果线程ID被重新分配或重新分配给其他的内存,则会随机加入或破坏一个不同的线程。你会考虑在最后一次编辑中添加一个链接到你的源吗?我相信你是从这里得到的,但我想先确认一下。不过,回答得很好@柯里森西:补充!
   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).