I wrote a simple thread pool with c++11 threads. On windows it behaves as intended but on linux it blocks. I assume that I programmed it wrong and it is just running on windows by coincidence.
The idea is to create the pool once and call run() multiple times, which runs the program once on all available threads, and returns afterwards without destroying the threads. The threads then wait for the next run and so on.
On windows this worked every time I tried it. On linux however only a single thread starts executing the program and after that nothing happens, so run() never returns.
I have included a only slightly condensed version of my source code because I thought the thing might be small enough. If someone is interested in taking a look I suspect loop() and wait_all() in the middle of the code section are the most relevant parts. I have also included the declaration as a reference in case the variable types are not clear from name/context.
Pool::Pool(uint32_t num_threads) : num_threads_(num_threads), uniques_(num_threads), threads_(num_threads) {
shared_.end = false;
for (uint32_t i = 0; i < num_threads; ++i) {
uniques_[i].wake = false;
threads_[i] = std::thread(loop, std::ref(uniques_[i]), std::ref(shared_));
}
}
void Pool::run(Program program) {
shared_.program = program;
wake_all();
wait_all();
}
void Pool::wake_all() {
for (size_t i = 0; i < uniques_.size(); ++i) {
uniques_[i].wake = true;
}
shared_.wake_signal.notify_all();
}
void Pool::wait_all() {
for (size_t i = 0; i < num_threads_; ++i) {
std::unique_lock<std::mutex> locker(uniques_[i].lock);
uniques_[i].done_signal.wait(locker, [&]{return !uniques_[i].wake;});
}
}
void Pool::loop(Unique& unique, Shared& shared) {
for (;;) {
std::unique_lock<std::mutex> locker(unique.lock);
shared.wake_signal.wait(locker, [&]{return unique.wake;});
if (shared.end) {
break;
}
// Do stuff... On linux only a single thread gets here
shared.program();
unique.wake = false;
locker.unlock();
unique.done_signal.notify_all();
}
}
// Declaration
class Pool {
public:
typedef std::function<void()> Program;
Pool(uint32_t num_threads);
void run(Program program);
private:
void wake_all();
void wait_all();
struct Unique {
std::condition_variable done_signal;
std::mutex lock;
bool wake;
};
struct Shared {
Program program;
std::condition_variable wake_signal;
bool end;
};
uint32_t num_threads_;
Shared shared_;
std::vector<Unique> uniques_;
std::vector<std::thread> threads_;
static void loop(Unique& unique, Shared& shared);
};
Aucun commentaire:
Enregistrer un commentaire