主线程是否在阻塞线程上运行?

Does the main thread run on blocking threads?

本文关键字:线程 运行 是否      更新时间:2023-10-16

当我开始研究 c++11 中的线程时,我认为.join()用于在主线程上进行阻塞操作,std::async()用于运行非阻塞线程。

在我看来,这个答案很好地解释了std:async()。 https://stackoverflow.com/a/15035157/1770034

但我想更好地了解连接方法。我找到了几个这样的例子: https://stackoverflow.com/a/11229853/1770034 从主线程仅创建 1 个线程。

然后我找到了这个 https://solarianprogrammer.com/2011/12/16/cpp-11-thread-tutorial/

来自网站的代码片段:

#include <iostream>
#include <thread>
static const int num_threads = 10;
//This function will be called from a thread
void call_from_thread(int tid) {
std::cout << "Launched by thread " << tid << std::endl;
}
int main() {
std::thread t[num_threads];
//Launch a group of threads
for (int i = 0; i < num_threads; ++i) {
t[i] = std::thread(call_from_thread, i);
}
std::cout << "Launched from the mainn";
//Join the threads with the main thread
for (int i = 0; i < num_threads; ++i) {
t[i].join();
}
return 0;
}

我对这部分感到好奇的部分就在这里:

//Join the threads with the main thread
for (int i = 0; i < num_threads; ++i) {
t[i].join();
}

如果主线程停止等待.join()完成,循环如何运行以加入更多线程?它的工作原理很棒!但是,为什么它会起作用?

为什么它以这种方式工作?这是我对它如何工作的印象。

  1. 主线程加入第一个线程。
  2. 主线程等到第一个线程完成。
  3. 第一个线程完成。
  4. 主线程继续进入 for 循环并加入第二个线程。
  5. 主线程等待第二个线程完成。

如果它继续循环通过 for 循环,主线程何时实际被阻塞等待?

编辑

例:

//Join the threads with the main thread
for (int i = 0; i < num_threads; ++i) {
t[i].join();
// --- Perform some long operation here ---
}

长期手术何时进行?

当我发布这个问题时,我不明白多线程到底发生了什么。

即使在阅读有关C++主题的几个教程时,究竟发生了什么仍然有点模糊。所以这是对实际发生的事情的解释。

为了简单起见,让我们使用以下代码:

#include <thread>
void my_function()
{
*** Some Code ***
}
int main()
{
std::thread threads[10]; //create 10 std::thread objects
for(int loop = 0; loop < 10; loop++)
{
threads[loop] = std::thread(my_function);
}
//Threads are executing on machine and main code is also running
for(int loop = 0; loop < 10; loop++)
{
threads[loop].join; //If threads[loop] is still running wait for it, otherwise keep moving forward.
}
return 0;
} //all 10 thread objects (threads) are going out of scope and their destructors are being called

在主线程的顶部(在主线程中),我们为堆栈上的 10 个线程对象创建空间。在第一个 for 循环中,我们实际上创建了一个std::thread,它将在单独的线程上调用my_function

假设我们有一个四核处理器,一个线程一次只能在一个处理器上运行。(完全是假设!主线程当前正在使用其中一个处理器,我们的 10 个线程中的一个将使用第二个处理器。其余 9 个中的一个将使用第三个,其余 8 个中的一个将使用第四个。

for循环之间,我们可以在主线程上执行我们想要的所有代码。(即:主线程未被阻塞)。接下来,我们进入第二个for循环。这个循环将遍历并告诉每个线程join.

假设线程 1-9 此时已执行,但我们仍在后台运行线程 10。当for循环加入线程 1 时。由于它已经完成,for循环再次运行。这在前 9 个线程中继续发生。现在我们join线程 10。它仍在运行,主线程现在将等待线程 10 完成。(如果您需要在某个时间点完成代码才能继续前进,这很好。

接下来,我们有return 0;,我们创建的std::thread超出了范围,因为它们是对象,因此调用析构函数。由于所有线程都连接到主线程,因此不会引发异常,一切都结束得很好。

如果我们想,"嘿,我不在乎线程是否完成,这个程序结束了。当调用std::thread析构函数时,std::thread对象会注意到有问题并引发std::terminate

如果我们真的不在乎线程何时完成或是否完成。我们可以使用detach.这将允许它运行,直到它完成其任务。如果它在 main 结束时仍在运行,线程将无一例外地死亡(现代操作系统会随着进程杀死它)。

什么是joinable? 如果您没有从调用方(在本例中为主线程)join线程或detach线程,则joinable为 true。如果要检查线程是否仍在运行,并且在运行之前不join它。您需要改用std::async。(C++11 可以判断 std::thread 是否处于活动状态吗?