多次调用pthread_join函数的工作原理是什么?

3
我正在重新使用pthread,并且pthread_join的定义让我感到困扰。
它说:“pthread_join()函数将挂起调用线程的执行,直到目标线程终止,除非目标线程已经终止。从成功的pthread_join()调用返回时,通过终止线程传递给pthread_exit()的值将在value_ptr引用的位置中提供。当pthread_join()成功返回时,目标线程已被终止。同时指定相同目标线程的多个同时调用pthread_join()的结果是未定义的。如果调用pthread_join()的线程被取消,则目标线程不应该分离。”
我试图理解如何在调用pthread_join以启动第二个线程之前,调用pthread_join来为一个线程调用,即使我想象中,第一个join已经挂起了主线程的执行并阻止了下一行的运行,直到从加入的线程内部调用pthread_exit。
特别地,我想象中,第一个pthread_join必须等待指定的线程调用pthread_exit,然后它才能继续。但是这并不是情况,因为我可以这样做:
#include <pthread.h>
#include <stdio.h>

int avail = 0;

void *consumer(void *unused)
{
    while (1) {
        if (avail > 0) {
            --avail;
            puts("consumed");
        }
    }
}

void *producer(void *unused)
{
    while (1) {
        ++avail;
        puts("produced");
    }
}

int main(int argc, char **argv)
{
    pthread_t c_thread;
    pthread_t p_thread; 
    pthread_create(&c_thread, 0, consumer, 0);
    pthread_create(&p_thread, 0, producer, 0);
    pthread_join(c_thread, 0);
    pthread_join(p_thread, 0);

    return 0;
}

忽略可能的竞态条件尝试减少代码大小,为什么两个线程都在工作,尽管第一个 join 暂停了主线程(因此,在我的看法中阻止了下一个 join 被调用)。
我真的很想了解这是如何工作的。
提前感谢。

2
我调用pthread_join()来等待一个线程结束,然后再调用pthread_join()来等待第二个线程结束。但是需要注意的是,pthread_join()并不会创建线程。另外,你的“问题”缺乏对你所看到的和期望看到的情况的精确描述。请注意,你对所看到的内容的解释比实际看到的内容更不重要。 - Ulrich Eckhardt
1
你可以添加一个睡眠调用或者调用scanf()等待输入,或者设置一个断点。调度程序在创建线程后不会立即切换到另一个线程。也就是说,你可以轻松地检查第二个pthread_join()是否被调用,或者至少第一个是否返回。 - Ulrich Eckhardt
好的,那就是说join基本上充当了一个非忙等待线程完成的角色,然后程序才会继续执行。这些线程确实是由pthread_create创建并启动的,但它们需要时间来实际运行,因为如果没有告诉主线程等待任何东西,main函数将很早就退出了。 - Dmytro
1
“…等待线程结束。”不是所有的线程都需要等待,只有当您调用 pthread_join 时特指您所指定的线程。被指定的线程的用户代码也不必直接调用 pthread_exit ,它可以简单地使用 return something;(请参见此 man 页面中的项目符号)。虽然这对于您来说可能不那么重要,但对于 C++ 程序员而言是极为重要的。 - WhozCraig
2个回答

5

线程是同时运行的,在调用pthread_create之后的某个时间开始。调用pthread_join与启动或运行线程无关,它只是等待线程退出。在您进入并阻止第一个join时,两个线程已经在运行,并且仍可运行,它们将继续运行。唯一被第一个join阻塞的是主线程。


你说得对,我发现如果我去掉连接操作,程序会提前退出,因为它根本不等待任何线程完成。如果我用忙循环代替连接操作 "while(1) {}", 线程仍然可以运行。谢谢! - Dmytro
程序在main函数返回时终止。 (我相信标准规定从main函数返回等同于调用exit函数)。这包括所有线程的终止。此时线程可能已经运行,也可能没有运行,这取决于线程如何被调度运行,这又取决于您的平台。 - Dark Falcon

0

线程不是在pthread_join中启动,而是在pthread_create中启动。我误导自己认为pthread_join用于实际启动线程,但它实际上是一个非忙等待特定线程返回的函数,在我的情况下,主线程在线程有机会调用puts函数之前就返回了。

我的代码中的第二个pthread_join实际上从未被调用,因为主线程确实被挂起在第一个pthread_join上,等待c_thread返回。在这种特殊情况下,第二个join是一个“无操作”,程序实际上永远不会到达它,因为消费者实际上从未返回。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接