Ответ 1
но библиотеке потоков также нужно беспокоиться о распределении потоков на ядра. это не работа операционной системы? Итак, каков настоящий Бенифит в использовании TBB над Boost?
Вы правы, библиотека потоковой обработки обычно не должна заботиться о привязке потоков к ядрам. И TBB этого не делает. TBB работает с задачами, а не с потоками. Планировщик TBB использует все ядра, выделяя пул потоков и позволяя ему динамически выбирать, какие задачи выполнять. Это основное преимущество над Boost, с помощью которого вам нужно будет вручную отображать доступную работу к потокам. И тогда TBB предлагает высокоуровневые конструкции, такие как parallel_for, parallel_pipeline и т.д., Которые могут использоваться для выражения наиболее распространенных параллельных шаблонов и скрыть все манипуляции с задачами.
Например, возьмите кусок кода, который вычисляет точки фрактала Мандельброта (взяты из 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 (я использую lambda для С++ 11 для краткости):
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 автоматически распределяет все итерации цикла по доступным ядрам (и вы не беспокоитесь о том, сколько) и динамически балансируете нагрузку, чтобы, если в каком-то потоке больше работы, другие потоки не просто ждут ее, но и помогают, максимизируя использование ЦП. Попробуйте реализовать его с помощью необработанных потоков, и вы почувствуете разницу:)