33

在我的新应用程序中,我可以灵活地决定将库用于多线程。到目前为止,我使用的是 pthread。现在想探索跨平台库。我在 TBB 和 Boost 上归零。我不明白 TBB 比 Boost 有什么好处。我试图找出 TBB 相对于 Boost 的优势:TBB Excerpts for wiki “相反,该库通过允许将操作视为“任务”来抽象对多个处理器的访问,这些操作由库的运行动态分配给各个内核- “

但是线程库甚至需要担心线程分配给内核。这不是操作系统的工作吗?那么使用 TBB 而不是 Boost 的真正好处是什么?

4

2 回答 2

35

但是线程库甚至需要担心线程分配给内核。这不是操作系统的工作吗?那么使用 TBB 而不是 Boost 的真正好处是什么?

你是对的,线程库通常不应该关心将线程映射到核心。而 TBB 没有。TBB 使用任务而不是线程进行操作。TBB 的调度程序通过分配线程池并让它动态选择要运行的任务来利用所有内核。这是与 Boost 相比的主要优势,您需要手动将可用工作映射到线程。然后 TBB 提供了高级构造,例如 parallel_for、parallel_pipeline 等,可用于表达最常见的并行模式,并隐藏所有与任务的操作。

例如,让我们来看一段计算 Mandelbrot 分形点的代码(取自http://warp.povusers.org/Mandelbrot/,省略了变量初始化):

for(unsigned y=0; y<ImageHeight; ++y)
{
    double c_im = MaxIm - y*Im_factor;
    for(unsigned x=0; x<ImageWidth; ++x)
    {
        double c_re = MinRe + x*Re_factor;

        double Z_re = c_re, Z_im = c_im;
        bool isInside = true;
        for(unsigned n=0; n<MaxIterations; ++n)
        {
            double Z_re2 = Z_re*Z_re, Z_im2 = Z_im*Z_im;
            if(Z_re2 + Z_im2 > 4)
            {
                isInside = false;
                break;
            }
            Z_im = 2*Z_re*Z_im + c_im;
            Z_re = Z_re2 - Z_im2 + c_re;
        }
        if(isInside) { putpixel(x, y); }
    }
}

现在要使其与 TBB 并行,您只需将最外层循环转换为 tbb::parallel_for (为简洁起见,我使用 C++11 lambda):

tbb::parallel_for(0, ImageHeight, [=](unsigned y)
{
    // the rest of code is exactly the same
    double c_im = MaxIm - y*Im_factor;
    for(unsigned x=0; x<ImageWidth; ++x)
    {
        ...
        // if putpixel() is not thread safe, a lock might be needed
        if(isInside) { putpixel(x, y); }
    }
});

TBB 将自动将所有循环迭代分布在可用内核上(并且您不必担心多少)并动态平衡负载,这样如果某个线程有更多工作要做,其他线程不仅会等待它,还会提供帮助,最大限度地利用 CPU利用率。尝试用原始线程来实现它,你会感觉到不同:)

于 2011-08-20T20:22:06.470 回答
10

英特尔 TBB 引入了它自己的线程池/调度器和执行模型(包括诸如parallel_for构造之类的东西),而 Boost 只有基本的线程管理功能(创建线程和同步原语,仅此而已。)使用 Boost 编写一个好的线程池是可能的,但很难-- TBB 已经带有一个高度优化的线程池。所以这完全取决于您的要求:如果您只需要“便携式 pthreads”,请使用 Boost,如果您需要更多,请使用 Intel TBB。

于 2011-08-20T07:59:31.100 回答