在Windows上创建缓慢的线程

时间:2014-11-21 09:11:28

标签: windows multithreading c++11

我已经使用C ++ 11工具将数字运算应用程序升级为多线程程序。它在Mac OS X上运行良好,但不受益于Windows上的多线程(Visual Studio 2013)。使用以下玩具程序

#include <iostream>
#include <thread>

void t1(int& k) {
    k += 1;
};

void t2(int& k) {
    k += 1;
};

int main(int argc, const char *argv[])
{
    int a{ 0 };
    int b{ 0 };

    auto start_time = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 10000; ++i) {
        std::thread thread1{ t1, std::ref(a) };
        std::thread thread2{ t2, std::ref(b) };
        thread1.join();
        thread2.join();
    }
    auto end_time = std::chrono::high_resolution_clock::now();
    auto time_stack = std::chrono::duration_cast<std::chrono::microseconds>(
        end_time - start_time).count();
    std::cout << "Time: " << time_stack / 10000.0 << " micro seconds" <<
        std::endl;

    std::cout << a << " " << b << std::endl;

    return 0;
}

我发现在Mac OS X上启动一个线程需要34微秒,在Windows上需要340微秒才能完成相同的操作。我在Windows方面做错了吗?这是编译器问题吗?

2 个答案:

答案 0 :(得分:7)

不是编译器问题(严格来说也不是操作系统问题)。

众所周知,创建线程是一项昂贵的操作。在Windows下,这是尤其 true(在clone之前的Linux下也是如此)。
此外,创建并加入一个线程必然很慢,而且并没有说明创建一个线程。加入假定线程已经退出,这只能在计划运行之后发生。因此,您的测量包括调度引入的延迟。就你所测量的时间实际上相当不错(它们可以轻松地长20倍!)。

然而,无论如何,产卵线是否都很慢并不重要。

真正的程序中创建20,000个基准测试线程是一个严重的错误。虽然创建数千(甚至数百万)个线程并非严格违法或不允许,但&#34;正确&#34;使用线程的方法是创建没有比大约CPU核心更多的线程。一个人不会一直创造非常短暂的线程。
可能有一些短命的,你可能创建一些额外的线程(例如阻止I / O),但你不想创建数百个或成千上万的。每个额外的线程(超出CPU核心数)意味着更多的上下文切换,更多的调度程序工作,更多的缓存压力,1MB的地址空间和每个线程64kB的物理内存(由于堆栈保留和提交粒度)。

现在,假设您在程序启动时创建了10个线程,根本不需要花费3毫秒。无论如何,程序启动需要几百毫秒(至少),没有人会注意到差异。

答案 1 :(得分:1)

Visual C ++使用并发运行时(特定于MS)来实现std.thread功能。直接调用任何并发运行时功能/函数时,它会创建一个默认的运行时对象(不会详细介绍)。或者,当您调用std.thread函数时,它与调用ConcRT函数的函数相同。

默认运行时(或者说,调度程序)的创建需要一些时间,因此它似乎需要一段时间。尝试创建一个std::thread对象,让它运行;然后执行benching标记代码(例如,上面的代码)。

编辑: