GrPPI  0.2
Generic and Reusable Parallel Pattern Interface
tbb/divideconquer.h
Go to the documentation of this file.
1 
21 #ifndef GRPPI_TBB_DIVIDECONQUER_H
22 #define GRPPI_TBB_DIVIDECONQUER_H
23 
24 #ifdef GRPPI_TBB
25 
26 #include "parallel_execution_tbb.h"
27 
28 #include <tbb/tbb.h>
29 
30 namespace grppi {
31 
32 template <typename Input, typename Divider, typename Solver, typename Combiner>
33 typename std::result_of<Solver(Input)>::type
35  Input & input,
36  Divider && divide_op, Solver && solve_op,
37  Combiner && combine_op,
38  std::atomic<int>& num_threads)
39 {
40  // Sequential execution fo internal implementation
42 
43  if (num_threads.load()<=0) {
44  return divide_conquer(seq, input, std::forward<Divider>(divide_op),
45  std::forward<Solver>(solve_op), std::forward<Combiner>(combine_op));
46  }
47 
48  auto subproblems = divide_op(input);
49 
50  if (subproblems.size()<=1) {
51  return solve_op(input);
52  }
53 
54  using Output = typename std::result_of<Solver(Input)>::type;
55  std::vector<Output> partials(subproblems.size()-1);
56  int division = 0;
57  tbb::task_group g;
58  auto i = subproblems.begin()+1;
59  for(i; i!=subproblems.end() && num_threads.load()>0; i++, division++) {
60  //THREAD
61  g.run(
62  [&ex, i, &partials, division, &divide_op, &solve_op, &combine_op,
63  &num_threads]()
64  {
65  partials[division] = internal_divide_conquer(ex, *i,
66  std::forward<Divider>(divide_op), std::forward<Solver>(solve_op),
67  std::forward<Combiner>(combine_op), num_threads);
68  }
69  );
70  //END TRHEAD
71  num_threads--;
72  }
73 
74  //Main thread works on the first subproblem.
75  for(i; i != subproblems.end(); i++){
76  partials[division] = divide_conquer(seq, *i,
77  std::forward<Divider>(divide_op), std::forward<Solver>(solve_op),
78  std::forward<Combiner>(combine_op));
79  }
80 
81  Output out = internal_divide_conquer(ex, *subproblems.begin(),
82  std::forward<Divider>(divide_op), std::forward<Solver>(solve_op),
83  std::forward<Combiner>(combine_op), num_threads);
84 
85  g.wait();
86 
87  for (auto && p : partials) { out = combine_op(out,p); }
88 
89  return out;
90 }
91 
113 template <typename Input, typename Divider, typename Solver, typename Combiner>
114 typename std::result_of<Solver(Input)>::type
116  Input & input,
117  Divider && divide_op, Solver && solve_op,
118  Combiner && combine_op)
119 {
120  // Sequential execution fo internal implementation
122 
123  std::atomic<int> num_threads{ex.concurrency_degree()-1};
124 
125  if (num_threads.load()<=0) {
126  return divide_conquer(seq, input, std::forward<Divider>(divide_op),
127  std::forward<Solver>(solve_op), std::forward<Combiner>(combine_op));
128  }
129 
130  auto subproblems = divide_op(input);
131  if (subproblems.size()<=1) {
132  return solve_op(input);
133  }
134 
135  using Output = typename std::result_of<Solver(Input)>::type;
136  std::vector<Output> partials(subproblems.size()-1);
137  int division = 0;
138  tbb::task_group g;
139 
140  auto i = subproblems.begin()+1;
141  for (i ; i!=subproblems.end() && num_threads.load()>0; i++, division++) {
142  //THREAD
143  g.run(
144  [&ex, i, &partials, division, &divide_op, &solve_op, &combine_op,
145  &num_threads]()
146  {
147  partials[division] = internal_divide_conquer(ex, *i,
148  std::forward<Divider>(divide_op), std::forward<Solver>(solve_op),
149  std::forward<Combiner>(combine_op), num_threads);
150  }
151  );
152  num_threads--;
153  //END TRHEAD
154  }
155  for(i; i != subproblems.end(); i++){
156  partials[division] = divide_conquer(seq, *i,
157  std::forward<Divider>(divide_op), std::forward<Solver>(solve_op),
158  std::forward<Combiner>(combine_op));
159  }
160  //Main thread works on the first subproblem.
161 
162  Output out;
163  if (num_threads.load()>0) {
164  out = internal_divide_conquer(ex, *subproblems.begin(),
165  std::forward<Divider>(divide_op), std::forward<Solver>(solve_op),
166  std::forward<Combiner>(combine_op), num_threads);
167  }
168  else {
169  out = divide_conquer(seq, *subproblems.begin(),
170  std::forward<Divider>(divide_op), std::forward<Solver>(solve_op),
171  std::forward<Combiner>(combine_op));
172  }
173 
174  g.wait();
175 
176  for (int i=0; i<partials.size(); i++){
177  out = combine_op(out , partials[i]);
178  }
179  return out;
180 }
181 
187 }
188 
189 #endif
190 
191 #endif
Definition: callable_traits.h:24
std::result_of< Solver(Input)>::type divide_conquer(parallel_execution_native &ex, Input &problem, Divider &&divide_op, Solver &&solve_op, Combiner &&combine_op)
Invoke Divide/conquer pattern with native parallel execution.
Definition: native/divideconquer.h:124
TBB parallel execution policy.
Definition: parallel_execution_tbb.h:37
int concurrency_degree() const noexcept
Get number of grppi trheads.
Definition: parallel_execution_tbb.h:73
Sequential execution policy.
Definition: sequential_execution.h:31
std::result_of< Solver(Input)>::type internal_divide_conquer(parallel_execution_native &p, Input &input, Divider &&divide_op, Solver &&solve_op, Combiner &&combine_op, std::atomic< int > &num_threads)
Definition: native/divideconquer.h:33