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

时间:2017-03-30 12:37:19

标签: c++ multithreading c++11

当我开始研究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 main\n";

    //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. 主线程等到第1个线程结束。
  3. 第一个线程结束。
  4. 主线程继续for循环并加入第二个线程。
  5. 主线程等到第2个线程结束。
  6. ...... ......
  7. 如果主线程实际上被阻止等待,它是否继续循环执行for循环?

    修改

    示例:

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

    什么时候会进行长时间的操作?

1 个答案:

答案 0 :(得分:1)

当我发布这个问题时,我并不完全了解多线程的确切情况。

即使在阅读有关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

在main的顶部(在主线程中),我们为堆栈上的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超出范围,因为它们是对象,所以调用析构函数。由于所有线程都连接到main,因此不会抛出任何异常,并且一切都很好地结束。

如果我们想,“嘿,我不在乎线程是否完成,这个程序结束了。”调用std::thread析构函数时,std::thread对象会发现错误并引发std::terminate

如果我们真的不关心线程何时完成或完成。我们可以使用detach。这将允许它运行直到完成任务。如果它仍然在main的末尾运行,则线程将毫无例外地死亡(现代操作系统将使用该进程终止它。)

什么是joinable?如果你没有joinable来自调用者的线程joindetach线程(在我们的例子中是主线程),那么join将是真的。如果你想检查一个线程是否仍在运行而不是std::async它,直到它为止。您需要使用v-on:input代替。 (Can C++11 tell if std::thread is active?