为什么不按顺序运行这些线程?

时间:2014-12-03 21:35:53

标签: c++ multithreading c++11

当我运行此代码时:

#include <iostream>
#include <thread>
#include <mutex>

std::mutex m;

int main()
{
    std::vector<std::thread> workers;
    for (int i = 0; i < 10; ++i)
    {
        workers.emplace_back([i]
        {
            std::lock_guard<std::mutex> lock(m);
            std::cout << "Hi from thread " << i << std::endl;
        });
    }

    std::for_each(workers.begin(), workers.end(), [] (std::thread& t)
    { t.join(); });
}

我得到output

Hi from thread 7
Hi from thread 1
Hi from thread 4
Hi from thread 6
Hi from thread 0
Hi from thread 5
Hi from thread 2
Hi from thread 3
Hi from thread 9
Hi from thread 8

即使我使用互斥锁一次只能访问一个线程。为什么输出不按顺序排列?

4 个答案:

答案 0 :(得分:19)

您的互斥锁实现的目标是不会同时打印两个线程。但是,他们仍在竞争哪个线程首先获得互斥锁。

如果你想进行串行执行,你可以完全避免线程。

答案 1 :(得分:6)

完全取决于调度订单线程的操作系统。你不能依赖任何订单。假设它完全是随机的。

答案 2 :(得分:3)

您正在将lambda传递给emplace_back,后者用作std :: thread构造函数的参数。请参阅cppreference.com下面的emplace_back复制/粘贴详细信息。

&#34;将新元素追加到容器的末尾。该元素是通过std :: allocator_traits :: construct构造的,它通常使用placement-new在容器提供的位置构造元素。参数args ...作为std :: forward(args)....&#34;

转发给构造函数

http://en.cppreference.com/w/cpp/container/vector/emplace_back

在完全构造std :: thread对象并运行lambda body定义的线程入口点之前,lambda体中的互斥锁没有任何影响。一些std :: threads可能在循环期间开始运行,或者线程可能在循环完成之后才开始运行。你无法以便携的方式解决这个问题。

在for循环中构造了向量中的所有std :: threads之后,操作系统决定线程的运行顺序,以及输出的随机顺序。< / p>

答案 3 :(得分:2)

执行顺序并不重要,您无法预测它,并且在给定的运行中它会随着时间的推移而发生变化。

您的设计绝不应以任何方式或形式依赖于线程执行顺序。

它远不止于此:如果N个线程正在等待同步对象(例如互斥锁),并且互斥锁被释放,则无法可靠且可移植地预测哪些等待线程将被唤醒并获取互斥锁接下来,无论其相对调度优先级如何。

非确定性使多线程编程变得困难: - )