quickpool  0.2.0
An easy-to-use, header-only work stealing thread pool in C++11
test.cpp
1 #include <iostream>
2 
3 #include "quickpool.hpp"
4 
5 int
6 main()
7 {
8 
9  // README contents --------------------------------------------
10  std::cout << "- Running contents from README: ";
11 
12  // Static access to a global pool
13  {
14  quickpool::push([] { /* some work */ });
15  quickpool::push([] { /* some work */ });
16  quickpool::wait(); // waits for all current jobs to finish
17  }
18 
19  // async
20  {
21  auto f = quickpool::async([] { return 1 + 1; });
22  // do something else ...
23  auto result = f.get(); // waits until done and returns result
24  }
26 
27  // extra arguments
28  {
29  auto work = [](const std::string& title, int i) {
30  // std::cout << title << ": " << i << std::endl;
31  };
32  quickpool::push(work, "first title", 5);
33  quickpool::async(work, "other title", 99);
35  }
36 
37  // Local thread pool
38  {
39  quickpool::ThreadPool pool; // thread pool with two threads
40  pool.push([] { /* some work */ });
41  pool.async([] { /* some work */ });
42  pool.wait(); // waits for all current jobs to finish
43  }
44 
45  // Task synchronization
46  {
47  std::vector<double> x(2); // shared resource
48  quickpool::TodoList todo_prod(2);
49  quickpool::TodoList todo_cons(2);
50 
51  auto job_prod = [&](int i, double val) {
52  x.at(i) = val;
53  todo_prod.cross();
54  };
55  auto job_cons = [&](int i) {
56  todo_prod.wait(); // waits for all producers to finish
57  // std::cout << x.at(i) << std::endl;
58  todo_cons.cross();
59  };
60 
61  quickpool::push(job_prod, 0, 1.337); // writes x[0]
62  quickpool::push(job_prod, 1, 3.14); // writes x[1]
63  quickpool::push(job_cons, 0); // reads x[0]
64  quickpool::push(job_cons, 1); // reads x[1]
65  todo_cons.wait(); // waits for all consumers to finish
66  }
67  std::cout << "OK" << std::endl;
69 
70  // unit tests ---------------------------------------
71  std::cout << "- unit tests: \t\r";
72  auto runs = 100;
73  for (auto run = 0; run < runs; run++) {
74  std::cout << "- unit tests: run " << run + 1 << "/" << runs << "\t\r"
75  << std::flush;
76 
77  // thread pool push
78  {
79  // std::cout << " * push: ";
80  std::vector<size_t> x(10000, 1);
81  // auto dummy = [&](size_t i) -> void { x[i] = 2 * x[i]; };
82  for (size_t i = 0; i < x.size(); i++)
83  quickpool::push([&](size_t i) -> void { x[i] = 2 * x[i]; }, i);
85 
86  size_t count_wrong = 0;
87  for (size_t i = 0; i < x.size(); i++) {
88  if (count_wrong += (x[i] != 2))
89  std::cout << x[i];
90  }
91  if (count_wrong > 0) {
92  throw std::runtime_error("static push gives wrong result");
93  }
94 
96  x = std::vector<size_t>(10000, 1);
97  for (size_t i = 0; i < x.size(); i++)
98  pool.push([&](size_t i) -> void { x[i] = 2 * x[i]; }, i);
99  pool.wait();
100 
101  count_wrong = 0;
102  for (size_t i = 0; i < x.size(); i++)
103  count_wrong += (x[i] != 2);
104  if (count_wrong > 0)
105  throw std::runtime_error("push gives wrong result");
106  // std::cout << "OK" << std::endl;
107  }
108 
109  // async()
110  {
111  // std::cout << " * async: ";
112  std::vector<size_t> x(10000, 1);
113  auto dummy = [&](size_t i) { return 2 * x[i]; };
114 
115  std::vector<std::future<size_t>> fut(x.size());
116  for (size_t i = 0; i < x.size(); i++)
117  fut[i] = quickpool::async(dummy, i);
118  for (size_t i = 0; i < x.size(); i++)
119  x[i] = fut[i].get();
120  quickpool::wait();
121 
122  size_t count_wrong = 0;
123  for (size_t i = 0; i < x.size(); i++)
124  count_wrong += (x[i] != 2);
125  if (count_wrong > 0)
126  throw std::runtime_error("static async gives wrong result");
127 
129  x = std::vector<size_t>(10000, 1);
130  std::vector<std::future<size_t>> fut2(x.size());
131  for (size_t i = 0; i < x.size(); i++)
132  fut2[i] = pool.async(dummy, i);
133  for (size_t i = 0; i < x.size(); i++)
134  x[i] = fut2[i].get();
135  pool.wait();
136 
137  count_wrong = 0;
138  for (size_t i = 0; i < x.size(); i++)
139  count_wrong += (x[i] != 2);
140  if (count_wrong > 0)
141  throw std::runtime_error("async gives wrong result");
142  // std::cout << "OK" << std::endl;
143  }
144 
145  // single threaded
146  {
147  // std::cout << " * single threaded: ";
148  quickpool::ThreadPool pool(0);
149  std::vector<size_t> x(1000, 1);
150  auto dummy = [&](size_t i) -> void { x[i] = 2 * x[i]; };
151 
152  for (size_t i = 0; i < x.size(); i++) {
153  pool.push(dummy, i);
154  }
155  pool.wait();
156 
157  size_t count_wrong = 0;
158  for (size_t i = 0; i < x.size(); i++)
159  count_wrong += (x[i] != 2);
160  if (count_wrong > 0)
161  throw std::runtime_error("single threaded gives wrong result");
162  // std::cout << "OK" << std::endl;
163  }
164 
165  // rethrows exceptions
166  {
167  // std::cout << " * exception handling: ";
169  pool.push([] { throw std::runtime_error("test"); });
170  for (size_t i = 0; i < 200; i++) {
171  pool.push([&] {
172  std::this_thread::sleep_for(std::chrono::milliseconds(20));
173  });
174  }
175 
176  try {
177  pool.wait();
178  } catch (const std::exception& e) {
179  if (e.what() == std::string("test")) {
180  // std::cout << "OK" << std::endl;
181  } else {
182  throw std::runtime_error("exception not rethrown");
183  }
184  }
185  }
186  }
187 
188  std::cout << "- unit tests: OK " << std::endl;
189 
190  return 0;
191 }
quickpool::async
auto async(Function &&f, Args &&... args) -> std::future< decltype(f(args...))>
executes a job asynchronously the global thread pool.
Definition: quickpool.hpp:450
quickpool::ThreadPool::wait
void wait()
waits for all jobs currently running on the global thread pool.
Definition: quickpool.hpp:411
quickpool::wait
void wait()
waits for all jobs currently running on the global thread pool.
Definition: quickpool.hpp:458
quickpool::TodoList
Todo list - a synchronization primitive.
Definition: quickpool.hpp:36
quickpool::ThreadPool::async
auto async(Function &&f, Args &&... args) -> std::future< decltype(f(args...))>
executes a job asynchronously the global thread pool.
Definition: quickpool.hpp:399
quickpool::ThreadPool
A work stealing thread pool.
Definition: quickpool.hpp:330
quickpool::ThreadPool::push
void push(Function &&f, Args &&... args)
pushes a job to the thread pool.
Definition: quickpool.hpp:384
quickpool::push
void push(Function &&f, Args &&... args)
Direct access to the global thread pool ----------------—.
Definition: quickpool.hpp:437