thread.h 1.5 KB
Newer Older
rusty1s's avatar
rusty1s committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#pragma once

#include <condition_variable>
#include <future>
#include <queue>
#include <thread>

// A simple C++11 Thread Pool implementation with `num_workers=1`.
// See: https://github.com/progschj/ThreadPool
class Thread {
public:
  Thread();
  ~Thread();
  template <class F> void run(F &&f);
  void synchronize();

private:
  bool stop;
  std::mutex mutex;
  std::thread worker;
  std ::condition_variable condition;
  std::queue<std::future<void>> results;
  std::queue<std::function<void()>> tasks;
};

inline Thread::Thread() : stop(false) {
  worker = std::thread([this] {
    while (true) {
      std::function<void()> task;
      {
        std::unique_lock<std::mutex> lock(this->mutex);
        this->condition.wait(
            lock, [this] { return this->stop || !this->tasks.empty(); });
        if (this->stop && this->tasks.empty())
          return;
        task = std::move(this->tasks.front());
        this->tasks.pop();
      }
      task();
    }
  });
}

inline Thread::~Thread() {
  {
    std::unique_lock<std::mutex> lock(mutex);
    stop = true;
  }
  condition.notify_all();
  worker.join();
}

template <class F> void Thread::run(F &&f) {
  auto task = std::make_shared<std::packaged_task<void()>>(
      std::bind(std::forward<F>(f)));
  results.emplace(task->get_future());
  {
    std::unique_lock<std::mutex> lock(mutex);
    tasks.emplace([task]() { (*task)(); });
  }
  condition.notify_one();
}

void Thread::synchronize() {
  if (results.empty())
    return;
  results.front().get();
  results.pop();
}