寻求 std::join 行为的说明

Looking for clarification of std::join behavior

我一直在学习更多关于多线程和锁定的知识,这使我找到了 http://www.cplusplus.com/reference/thread/thread/join/

提供的基本示例

该页面提供的基本解释是:

The function returns when the thread execution has completed.

好的,这听起来像是我们启动了一个线程,当我们启动的线程完成时我们将恢复调用线程。

以下是该网站的一些示例代码,我已将打印语句添加到其中。

#include <iostream>
#include <thread>
#include <mutex>
#include <unistd.h>

std::mutex mtx;

void print_block (int n, char c) {
    mtx.lock();
    for (int i = 0; i < n; i++)
    {
        std::cout << c;
    }
    std::cout << std::endl ;
    mtx.unlock();

    return;
}

int main()
{
    std::thread th1(print_block, 50, '*');
    std::thread th2(print_block, 60, '$');

    th1.join();
    //my print statement
    std::cout << "In between thread joins" << std::endl;
    th2.join();
    
    return 0;
}

根据我看到的连接描述,我希望输出为:

**************************************************

In between thread joins

$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$

我的逻辑是:

  1. 主线程调用 th1.join,因此主线程暂停执行,直到 th1.join 完成。

  2. 第1次打印出star后执行完成,然后我的打印语句执行

  3. th2 执行开始和结束

实际情况并非如此,th2可以在th1之前执行,我的打印语句通常是最后出来的。 join 实际上对主线程做了什么?它似乎并没有像我一直在线阅读那样实际阻止它。

无论如何,我的解释毫无意义,因为它似乎与单线程进程相同。求助!

TLDR;

调用 join 时到底发生了什么?新线程开始了,但是主线程会发生什么?如果主线程确实阻塞了,为什么我的例子不是这样?

谢谢

编辑:

我想我明白了。出于某种原因,我认为 th1 在调用 join 时开始执行。 th1 在调用构造函数时开始执行。 Join 会阻塞主线程,直到 th1 开始执行后执行完毕。谢谢大家!

那个例子不好(原因如下);

What really happens when you call join? The new thread begins, but what happens to the main thread? If the main thread does block, why isn't my example the case?

th1.join() 将阻止 当前线程 的执行(在这种情况下,函数 main() 是 运行 的执行线程) 直到由 th1 表示的执行线程完成并且 returns.

现在,这与 th2 是否在 th1 之前完成无关 - (不能保证线程 th1 进入函数并在线程 [=14= 之前获取锁]).该方法只是说,“th1 完成之前不要继续 ”。

所以,是的,th2 可能会在 th1 之前完成,但是

std::cout << "In between thread joins" << std::endl;

th1 完成之前永远不会执行。


不好的例子:

  • 关于异常安全。更喜欢std::lock_guard。以后请更喜欢使用cppreference.com
  • 你的 int main() 中的 std::cout ... 没有受到保护,是的,std::cout 没有竞争,但在被多线程使用时不能避免字符输出的交错
  • 如果您需要某些函数之间的相对顺序,std::thread 可能不是您想要使用的。而且,更喜欢更高的抽象,例如 std::async.
  • codewise,即使你的 int main() 中的 std::cout ... 被假定为不可分割的交易,将 th1.join() 放在它之前,将 th2.join() 放在它之后只是一种欺骗.我会让连接在代码上相互跟随。