The previous article about Intel Threading Building Blocks discussed the advantages of this library and also looked at an example of the parallel_for algorithm. Let’s look at an example of using the parallel_reduce algorithm, which differs from the parallel_for function in that it allows partial results obtained in parallel threads to be combined.

First of all, you need to include the necessary header files:

`#include

include

include

include

* This source code was highlighted with Source Code Highlighter.`

Here stdio.h is used to include the printf function (output to the screen), blocked_range.h for using the blocked_range class (a blocked range), parallel_reduce.h for including the corresponding algorithm, and task_scheduler_inti.h for including the task scheduler.

As mentioned earlier, the standard Intel TBB algorithms — parallel_for, parallel_reduce — use the concept of a task class. The example below shows such a class for solving the problem of finding the value of the constant Pi (the example was inspired by an Intel contest, as well as by my student’s independent work). The idea of finding the number is to compute the area of a curvilinear trapezoid, which is approximated by a large number of rectangles. The more rectangles there are, the more accurate the value, but the more time is required for the computation. An illustration of this problem can be seen on the “http://www86.wolframalpha.com/input/?i=integral+4.0/(1.0+%2B+x+*+x),+x+from+0.0+to+1.0” site.

`// Класс-задача, отвечает за подсчет значения пи на заданном диапазаоне

class PiCalculation {

private: 

// Количество шагов в интервале, влияет на точность   

long num_steps;   // Ширина шага   double step; public: // Частичное значение пи   double pi;   // Вычислить частичное значение пи на заданном диапазоне   void operator () (const tbb::blocked_range<long> &r)   {     double sum = 0.0;     long end = r.end();     for (int i = r.begin(); i != end; i++)     {       double x = (i + 0.5) * step;       sum += 4.0/(1.0 + x * x);     }     pi += sum * step;   }   // Объеденить частичные результаты   void join(PiCalculation &p)   {     pi += p.pi;   }   // Разделяющий конструктор   PiCalculation(PiCalculation &p, tbb::split)   {     pi = 0.0;     num_steps = p.num_steps;     step = p.step;   }      // Конструктор   PiCalculation(long steps)   {     pi = 0.0;     num_steps = steps;     step = 1./(double)num_steps;   } }; * This source code was highlighted with Source Code Highlighter.`

The following two methods are important in this class: operator () and join.

The method void operator () (const blocked_range &r) computes a partial result over the interval [r.begin, r.end). The Intel TBB library and the blocked_range class take care of recursively splitting the original iteration space and “feeding” it in small portions to the operator () method. The result is accumulated in the variable pi, which is private to the thread. It is guaranteed that operator () for a single class will be called only from one thread, so errors such as “data races” (data races, race conditions) are ruled out.

The method void join (PiCalculation &p) sums the partial results of different threads. This is where an important difference between the Intel TBB library and the OpenMP and MPI libraries shows up: in those, the number of operations for combining partial results (reduction) is limited. Intel TBB makes it possible to implement arbitrary functions for combining results in the body of the join method.

Let’s look at starting the parallel_reduce algorithm.

<font size="2" face="Courier New" color="black"><font color="#0000ff">int</font> main() {   <font color="#008000">// Инициализация библиотеки Intel TBB</font>   tbb::task_scheduler_init init;   <font color="#008000">// Количество итераций</font>   <font color="#0000ff">const</font> <font color="#0000ff">long</font> steps = 100000000;   <font color="#008000">// Создание объекта-задачи по вычислению пи</font>   <font color="#008000">// Передается параметр: количество итераций</font>   PiCalculation pi(steps);   <font color="#008000">// Запуск алгоритма parallel_reduce над диапазоном [0, steps)</font>   tbb::parallel_reduce(tbb::blocked_range<<font color="#0000ff">long</font>>(0, steps, 1000000), pi);   printf (<font color="#A31515">"Pi is %3.20f\n"</font>, pi.pi);   <font color="#0000ff">return</font> 0; } </font> <font size="1" color="gray">* This source code was highlighted with [<font size="1" color="gray">Source Code Highlighter</font>](http://virtser.net/blog/post/source-code-highlighter.aspx).</font>

To do this, you need to perform the following steps: create an Intel TBB task scheduler object, create a PiCalculation task object, and call the parallel_reduce function. Here the function takes two parameters. The first is the range class. In our case, we specify the number of iterations [0, steps), i.e., when computing the integral from 0 to 1, steps = 100 000 000 steps will be used. The second parameter is a reference to the task object, which, after returning from the parallel_reduce function, will contain the value of pi.