Skip to content

Instantly share code, notes, and snippets.

@carlchen0928
Last active June 17, 2019 20:36
Show Gist options
  • Save carlchen0928/e3f24dadae3df7cdb806 to your computer and use it in GitHub Desktop.
Save carlchen0928/e3f24dadae3df7cdb806 to your computer and use it in GitHub Desktop.
Simple thread pool. Don't support user wait all task done.
#include "join_threads.h"
#include "threadsafe_subtle_queue.cpp"
#include "threadsafe_exceptionsafe_queue.cpp"
#include <thread>
#include <vector>
#include <atomic>
/*
* Simplest thread pool implementation, exception safe.
* Don't support user wait all task finish.
* It will never stop if everything goes will.
*/
class simple_threadpool
{
public:
explicit simple_threadpool()
: _done(false), _joiner(_threads)
{
int n = std::thread::hardware_concurrency();
try
{
// printf("creating threads...\n");
for (int i = 0; i < n; i++)
{
_threads.push_back(
std::thread(&simple_threadpool::work, this));
}
// printf("threads created.\n");
}
catch (...)
{
// When exception happend, send signal to stop all
// sub threads. Than _joiner will wait all threads
// than have been created.
_done = true;
throw;
}
}
~simple_threadpool()
{
// Must be called before data member's dtor.
_done = true;
}
template <class funciontype>
void submit(funciontype f)
{
// printf("pushing f...\n");
_work_queue.push(std::function<void()>(f));
}
private:
/*
* Variables must be declaration as fowllowing sequence.
* When dtor, _done and _work_queue should dtor after _threads
* because we can not dtor _work_queue until all threads stop.
* The same as _joiner and _threads.
*/
std::atomic_bool _done;
// threadsafe_exceptionsafe_queue<std::function<void()> > _work_queue;
threadsafe_subtle_queue<std::function<void()> > _work_queue;
std::vector<std::thread> _threads;
// when dtor, _done must be set to true.
// all child threads are closing.
join_threads _joiner; // RAII for thread, dtor call join
void work()
{
while (!_done)
{
std::function<void()> task;
if (_work_queue.try_pop(task))
{
// printf("starting execute function\n");
task();
// printf("executing function done!\n");
}
else
{
// printf("empyt queue...\n");
std::this_thread::yield();
}
}
}
};
#include <thread>
#include <vector>
class join_threads
{
public:
explicit join_threads(std::vector<std::thread>& threads)
: _threads(threads)
{}
~join_threads()
{
for (int i = 0; i < _threads.size(); ++i)
{
if (_threads[i].joinable())
{
_threads[i].join();
}
}
}
private:
// Must be a reference.
// Thread object can not be shared.
// Copy ctor and copy assignment declared privatly.
// But we can use move to transfer thread object.
std::vector<std::thread>& _threads;
};
#include "simple_threadpool.cpp"
#include <stdio.h>
#include <thread>
#include <iostream>
#include <memory>
// #include "threadsafe_subtle_queue.cpp"
void func()
{
printf("thread %d called\n", std::this_thread::get_id());
// printf("hahah\n");
}
int main()
{
simple_threadpool pool;
for (int i = 0; i < 20; i++)
pool.submit(func);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment