I am trying to write a ThreadPool class
class ThreadPool {
public:
ThreadPool(size_t numberOfThreads):isAlive(true) {
for(int i =0; i < numberOfThreads; i++) {
workerThreads.push_back(std::thread(&ThreadPool::doJob, this));
}
#ifdef DEBUG
std::cout<<"Construction Complete"<<std::endl;
#endif
}
~ThreadPool() {
#ifdef DEBUG
std::cout<<"Destruction Start"<<std::endl;
#endif
isAlive = false;
conditionVariable.notify_all();
waitForExecution();
#ifdef DEBUG
std::cout<<"Destruction Complete"<<std::endl;
#endif
}
void waitForExecution() {
for(std::thread& worker: workerThreads) {
worker.join();
}
}
void addWork(std::function<void()> job) {
#ifdef DEBUG
std::cout<<"Adding work"<<std::endl;
#endif
std::unique_lock<std::mutex> lock(lockListMutex);
jobQueue.push_back(job);
conditionVariable.notify_one();
}
private:
// performs actual work
void doJob() {
// try {
while(isAlive) {
#ifdef DEBUG
std::cout<<"Do Job"<<std::endl;
#endif
std::unique_lock<std::mutex> lock(lockListMutex);
if(!jobQueue.empty()) {
#ifdef DEBUG
std::cout<<"Next Job Found"<<std::endl;
#endif
std::function<void()> job = jobQueue.front();
jobQueue.pop_front();
job();
}
conditionVariable.wait(lock);
}
}
// a vector containing worker threads
std::vector<std::thread> workerThreads;
// a queue for jobs
std::list<std::function<void()>> jobQueue;
// a mutex for synchronized insertion and deletion from list
std::mutex lockListMutex;
std::atomic<bool> isAlive;
// condition variable to track whether or not there is a job in queue
std::condition_variable conditionVariable;
};
I am adding work to this thread pool from my main thread. My problem is calling waitForExecution() results in forever waiting main thread. I need to be able to terminate threads when all work is done and continue main thread execution from there. How should I proceed here?
The first step when writing a robust thread pool is to split the queue from the management of threads. A thread-safe queue is hard enough to write by its own, and managing threads similarly.
A thread safe queue looks like:
template<class T>
struct threadsafe_queue {
boost::optional<T> pop() {
std::unique_lock<std::mutex> l(m);
cv.wait(l, [&]{ aborted || !data.empty(); } );
if (aborted) return {};
return data.pop_front();
}
void push( T t )
{
std::unique_lock<std::mutex> l(m);
if (aborted) return;
data.push_front( std::move(t) );
cv.notify_one();
}
void abort()
{
std::unique_lock<std::mutex> l(m);
aborted = true;
data = {};
cv.notify_all();
}
~threadsafe_queue() { abort(); }
private:
std::mutex m;
std::condition_variable cv;
std::queue< T > data;
bool aborted = false;
};
where pop returns nullopt when the queue is aborted.
Now our thread pool is easy:
struct threadpool {
explicit threadpool(std::size_t n) { add_threads(n); }
threadpool() = default;
~threadpool(){ abort(); }
void add_thread() { add_threads(1); }
void add_threads(std::size_t n)
{
for (std::size_t i = 0; i < n; ++i)
threads.push_back( std::thread( [this]{ do_thread_work(); } ) );
}
template<class F>
auto add_task( F && f )
{
using R = std::result_of_t< F&() >;
auto pptr = std::make_shared<std::promise<R>>();
auto future = pptr.get_future();
tasks.push([pptr]{ (*pptr)(); });
return future;
}
void abort()
{
tasks.abort();
while (!threads.empty()) {
threads.back().join();
threads.pop_back();
}
}
private:
threadsafe_queue< std::function<void()> > tasks;
std::vector< std::thread > threads;
void do_thread_work() {
while (auto f = tasks.pop()) {
(*f)();
}
}
};
note that if you abort, outstanding future's are filled with a broken promise exception.
Worker threads stop running when the queue they are feeding from is aborted. The main thread on abort() will wait for the worker threads to finish (as is wise).
This does mean that worker thread tasks must also terminate, or the main thread will hang. There is no way to avoid this; often, your worker threads' tasks need to cooperate to get a message saying they should abort early.
Boost has a thread pool that integrates with its threading primitives and permits a less cooperative abort; in it, all mutex type operations implicitly check for an abort flag, and if they see it the operation throws.
How should I proceed here?
Well, you should learn to use your debugger, which should show you exactly where each of the threads you want to join is stopped.
I'm going to tell you what looks wrong, but strongly encourage you to do that first. It's invaluable.
OK, now: your condition variable loop is wrong.
The correct pattern is the one that behaves like the second form, with the predicate argument, here:
while (!pred()) {
wait(lock);
}
Specifically, if your predicate is true, you must not call wait. You may never be woken again, because the predicate never became false in the first place!
Try
// wait until we have something to do
while(jobQueue.empty() && isAlive) {
conditionVariable.wait(lock);
}
// unless we're exiting, we must have a job
if (isAlive) {
#ifdef DEBUG
std::cout<<"Next Job Found"<<std::endl;
#endif
std::function<void()> job = jobQueue.front();
jobQueue.pop_front();
job();
}
Imagine your thread is running a job when you call notify_all - it will call wait after the notification has already happened, and it isn't coming again. Since it doesn't check isAlive between finishing the job and calling wait, it's going to wait forever.
Even without the shutdown problem it would be wrong, because it should keep consuming jobs while there is work to do, instead of blocking every time it finishes one. Which reminds me of the last issue - you should probably unlock the mutex while executing the job (and re-lock it afterwards) - otherwise your pool is single-threaded.
Related
I'd like to implement a processing loop in a worker thread so that it processes data from a queue when there's something and blocks (the thread sleeps) otherwise...is this even possible? Should also work without any noticeable delays.
Something simple like this:
std::deque<Foo> queue;
void worker()
{
while (active) {
blockAndWaitForData();
while (!queue.empty()) {
doSomething(queue.front());
queue.pop_front();
}
}
}
Of course the queue would need to be locked plus some other details.
The Linux API could also be used directly if needed.
There is something that will suit your needs in C++11 standard. It is condition_variable. It allows you to wait until it is notified by other thread. So your worker could wait until producer notifies it like this. Note this is very dumbed down example and in most situations insufficent but gives you gist how to do it
std::deque<int> q;
std::mutex m;
std::condition_variable cv;
void worker() {
while (active) {
std::deque<int> vals;
{
std::unique_lock<std::mutex> l(m);
cv.wait(l, []{return q.empty();});
vals = std::move(q);
q.clear();
}
for (const auto& val : vals)
doSomething(val);
}
}
void producer() {
while (active) {
{
std::unique_lock<std::mutex> l(m);
q.push_back(produce());
}
cv.notify_one();
}
}
My case looks like this: The program uses two threads, let's call them "Sender" and "Recipient" because it is a mechanism of interprocess communication.
The "Sender" thread after sending the message stops at the condition provided by std::condition_variable and the .wait (Lock) function. The "Recipient" thread informs the waiting thread about the response to his message using .notify_one().
I'm happy with the way it works, but I want to add the ability to handle the timeout.
I prepared the following class (I would like it to be universal so the notification function is defined from the external class) but I'm sure that it can be implemented better. I wanted to avoid a lot of CPU usage, that's why I used std::this_thread::sleep_for, but I suppose that it can be somehow replaced with std::this_thread::yield(). I would like to use eg std::future_status, but I do not know how to do it. How can this be improved? I can use std c++11 or boost 1.55.
class Timer
{
private:
int MsLimit;
std::atomic<bool> Stop;
std::atomic<bool> LimitReached;
std::thread T;
std::mutex M;
std::function<void()> NotifyWaitingThreadFunction;
void Timeout()
{
std::unique_lock<std::mutex> Lock(M);
std::chrono::system_clock::time_point TimerStart = std::chrono::system_clock::now();
std::chrono::duration<long long, std::milli> ElapsedTime;
unsigned int T = 0;
do
{ std::this_thread::sleep_for(std::chrono::milliseconds(5));
std::chrono::system_clock::time_point TimerEnd = std::chrono::system_clock::now();
ElapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(TimerEnd - TimerStart);
T+=ElapsedTime.count();
if((T > MsLimit) && (!Stop))
{ LimitReached = true;
Stop = true;
}
}while(!Stop);
if(LimitReached)
{
NotifyWaitingThreadFunction();
}
}
public:
Timer(int Milliseconds) : MsLimit(Milliseconds)
{
}
void StartTimer()
{
Stop = false;
LimitReached = false;
T = std::thread(&Timer::Timeout,this);
}
void StopTimer()
{
std::unique_lock<std::mutex> Lock(M);
Stop = true;
LimitReached = false;
}
template<class T>
void AssignFunction(T* ObjectInstance, void (T::*MemberFunction)())
{
NotifyWaitingThreadFunction = std::bind(MemberFunction,ObjectInstance);
}
};
Your solution has one fault - do while loop is executed until MsLimit is elapsed. After Timeout started, M mutex is blocked and the call of StopTimer cannot break loop, because stop in StopTimer is set on true when M is released in Timeout what happens if (T > MsLimit) returns true and function ends. BTW, the use of mutex is redundant, because Stop is atomic.
You can use one of timers from boost library instead of creating your own one.
The code below uses boost::asio::high_resolution_timer (boost 1.55 version has it):
class Timer
{
public:
Timer (int ms)
: timer(io), ms(ms) {}
~Timer() {if(t.joinable()) t.join();}
void Start() {
t = std::thread( [this]()
{
timer.expires_from_now(std::chrono::milliseconds(ms));
timer.async_wait([this](const boost::system::error_code& ec) // start async wait
{ // lambda is called when timeout expired or error occures
if (!ec) // if there is no error, call function
NotifyWaitingThreadFunction();
});
io.run(); // process async operations
});
}
void Stop() {
timer.cancel();
}
template<class T>
void AssignFunction(T* ObjectInstance, void (T::*MemberFunction)())
{
NotifyWaitingThreadFunction = std::bind(MemberFunction,ObjectInstance);
}
private:
boost::asio::io_service io; // needed for timer
boost::asio::high_resolution_timer timer;
std::thread t;
int ms;
std::function<void()> NotifyWaitingThreadFunction;
};
In Start method thread is created where we set value of timeout in ms, timer is started by async_wait. Lambda passed into async_wait is called when timeout expired or an error occures. So if there is no error, you can call NotifyWaitingThreadFunction. To stop timer use Stop method. Stop cancels started aynchronous operation then lambda is called with ec == boost::asio::error::operation_aborted. In this case lambda ends without calling NotifyWaitingThreadFunction.
I'm struggling to implement a thread-safe reference-counted queue. The idea is that I have a number of tasks that each maintain a shared_ptr to a task manager that owns the queue. Here is a minimal implementation that should encounter that same issue:
#include <condition_variable>
#include <deque>
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
namespace {
class TaskManager;
struct Task {
std::function<void()> f;
std::shared_ptr<TaskManager> manager;
};
class Queue {
public:
Queue()
: _queue()
, _mutex()
, _cv()
, _running(true)
, _thread([this]() { sweepQueue(); })
{
}
~Queue() { close(); }
void close() noexcept
{
try {
{
std::lock_guard<std::mutex> lock(_mutex);
if (!_running) {
return;
}
_running = false;
}
_cv.notify_one();
_thread.join();
} catch (...) {
std::cerr << "An error occurred while closing the queue\n";
}
}
void push(Task&& task)
{
std::unique_lock<std::mutex> lock(_mutex);
_queue.emplace_back(std::move(task));
lock.unlock();
_cv.notify_one();
}
private:
void sweepQueue() noexcept
{
while (true) {
try {
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] { return !_running || !_queue.empty(); });
if (!_running && _queue.empty()) {
return;
}
if (!_queue.empty()) {
const auto task = _queue.front();
_queue.pop_front();
task.f();
}
} catch (...) {
std::cerr << "An error occurred while sweeping the queue\n";
}
}
}
std::deque<Task> _queue;
std::mutex _mutex;
std::condition_variable _cv;
bool _running;
std::thread _thread;
};
class TaskManager : public std::enable_shared_from_this<TaskManager> {
public:
void addTask(std::function<void()> f)
{
_queue.push({ f, shared_from_this() });
}
private:
Queue _queue;
};
} // anonymous namespace
int main(void)
{
const auto manager = std::make_shared<TaskManager>();
manager->addTask([]() { std::cout << "Hello world\n"; });
}
The problem I find is that on rare occasions, the queue will try to invoke its own destructor within the sweepQueue method. Upon further inspection, it seems that the reference count on the TaskManager hits zero once the last task is dequeued. How can I safely maintain the reference count without invoking the destructor?
Update: The example does not clarify the need for the std::shared_ptr<TaskManager> within Task. Here is an example use case that should illustrate the need for this seemingly unnecessary ownership cycle.
std::unique_ptr<Task> task;
{
const auto manager = std::make_shared<TaskManager>();
task = std::make_unique<Task>(someFunc, manager);
}
// Guarantees manager is not destroyed while task is still in scope.
The ownership hierarchy here is TaskManager owns Queue and Queue owns Tasks. Tasks maintaining a shared pointer to TaskManager create an ownership cycle which does not seem to serve a useful purpose here.
This is the ownership what is root of the problem here. A Queue is owned by TaskManager, so that Queue can have a plain pointer to TaskManager and pass that pointer to Task in sweepQueue. You do not need std::shared_pointer<TaskManager> in Task at all here.
I'd refactor the queue from the thread first.
But to fix your problem:
struct am_I_alive {
explicit operator bool() const { return m_ptr.lock(); }
private:
std::weak_ptr<void> m_ptr;
};
struct lifetime_tracker {
am_I_alive track_lifetime() {
if (!m_ptr) m_ptr = std::make_shared<bool>(true);
return {m_ptr};
}
lifetime_tracker() = default;
lifetime_tracker(lifetime_tracker const&) {} // do nothing, don't copy
lifetime_tracker& operator=(lifetime_tracker const&){ return *this; }
private:
std::shared_ptr<void> m_ptr;
};
this is a little utility to detect if we have been deleted. It is useful in any code that calls an arbitrary callback whose side effect could include delete(this).
Privately inherit your Queue from it.
Then split popping the task from running it.
std::optional<Task> get_task() {
std::unique_lock<std::mutex> lock(_mutex);
_cv.wait(lock, [this] { return !_running || !_queue.empty(); });
if (!_running && _queue.empty()) {
return {}; // end
}
auto task = _queue.front();
_queue.pop_front();
return task;
}
void sweepQueue() noexcept
{
while (true) {
try {
auto task = get_task();
if (!task) return;
// we are alive here
auto alive = track_lifetime();
try {
(*task).f();
} catch(...) {
std::cerr << "An error occurred while running a task\n";
}
task={};
// we could be deleted here
if (!alive)
return; // this was deleted, get out of here
}
} catch (...) {
std::cerr << "An error occurred while sweeping the queue\n";
}
}
}
and now you are safe.
After that you need to deal with the thread problem.
The thread problem is that you need your code to destroy the thread from within the thread it is running. At the same time, you also need to guarantee that the thread has terminated before main ends.
These are not compatible.
To fix that, you need to create a thread owning pool that doesn't have your "keep alive" semantics, and get your thread from there.
These threads don't delete themselves; instead, they return themselves to that pool for reuse by another client.
At shutdown, those threads are blocked on to ensure you don't have code running elsewhere that hasn't halted before the end of main.
To write such a pool without your inverted dependency mess, split the queue part of your code off. This queue owns no thread.
template<class T>
struct threadsafe_queue {
void push(T);
std::optional<T> pop(); // returns empty if thread is aborted
void abort();
~threadsafe_queue();
private:
std::mutex m;
std::condition_variable v;
std::deque<T> data;
bool aborted = false;
};
then a simple thread pool:
struct thread_pool {
template<class F>
std::future<std::result_of_t<F&()>> enqueue( F&& f );
template<class F>
std::future<std::result_of_t<F&()>> thread_off_now( F&& f ); // starts a thread if there aren't any free
void abort();
void start_thread( std::size_t n = 1 );
std::size_t count_threads() const;
~thread_pool();
private:
threadsafe_queue< std::function<void()> > tasks;
std::vector< std::thread > threads;
static void thread_loop( thread_pool* pool );
};
make a thread pool singleton. Get your threads for your queue from thread_off_now method, guaranteeing you a thread that (when you are done with it) can be recycled, and whose lifetime is handled by someone else.
But really, you should instead be thinking with ownership in mind. The idea that tasks and task queues mutually own each other is a mess.
If someone disposes of a task queue, it is probably a good idea to abandon the tasks instead of persisting it magically and silently.
Which is what my simple thread pool does.
I am using a simple thread pool as below-
template<typename T>
class thread_safe_queue // thread safe worker queue.
{
private:
std::atomic<bool> finish;
mutable std::mutex mut;
std::queue<T> data_queue;
std::condition_variable data_cond;
public:
thread_safe_queue() : finish{ false }
{}
~thread_safe_queue()
{}
void setDone()
{
finish.store(true);
data_cond.notify_one();
}
void push(T new_value)
{
std::lock_guard<std::mutex> lk(mut);
data_queue.push(std::move(new_value));
data_cond.notify_one();
}
void wait_and_pop(T& value)
{
std::unique_lock<std::mutex> lk(mut);
data_cond.wait(lk, [this]
{
return false == data_queue.empty();
});
if (finish.load() == true)
return;
value = std::move(data_queue.front());
data_queue.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lk(mut);
return data_queue.empty();
}
};
//Thread Pool
class ThreadPool
{
private:
std::atomic<bool> done;
unsigned thread_count;
std::vector<std::thread> threads;
public:
explicit ThreadPool(unsigned count = 1);
ThreadPool(const ThreadPool & other) = delete;
ThreadPool& operator = (const ThreadPool & other) = delete;
~ThreadPool()
{
done.store(true);
work_queue.setDone();
// IF thread is NOT marked detached and this is uncommented the worker threads waits infinitely.
//for (auto &th : threads)
//{
// if (th.joinable())
// th.join();
// }
}
void init()
{
try
{
thread_count = std::min(thread_count, std::thread::hardware_concurrency());
for (unsigned i = 0; i < thread_count; ++i)
{
threads.emplace_back(std::move(std::thread(&ThreadPool::workerThread, this)));
threads.back().detach();
// here the problem is if i dont mark it detatched thread infinitely waits for condition.
// if i comment out the detach line and uncomment out comment lines in ~ThreadPool main threads waits infinitely.
}
}
catch (...)
{
done.store(true);
throw;
}
}
void workerThread()
{
while (true)
{
std::function<void()> task;
work_queue.wait_and_pop(task);
if (done == true)
break;
task();
}
}
void submit(std::function<void(void)> fn)
{
work_queue.push(fn);
}
};
The usage is like :
struct start
{
public:
ThreadPool::ThreadPool m_NotifPool;
ThreadPool::ThreadPool m_SnapPool;
start()
{
m_NotifPool.init();
m_SnapPool.init();
}
};
int main()
{
start s;
return 0;
}
I am running this code on visual studio 2013. The problem is when main thread exits. The program crashes. It throws exception.
Please help me with what am i doing wrong? How do i stop the worker thread properly? I have spent quite some time but still figuring out what is the issue.
Thanks for your help in advance.
I am not familiar with threads in c++ but have worked with threading in C. In C what actually happens is when you creates child threads of from the main thread then you have to stop the main thread until the childs finishes. If main exits the threads becomes zombie. I think C don't throw an exception in case of Zombies. And may be you are getting exception because of these zombies only. Try stopping the main until the childs finishes and see if it works.
When main exits, detached threads are allowed to continue running, however, object s is destroyed. So, as your threads attempt to access members of object s, you are running into UB.
See accepted answer of this question for more details about your issue : What happens to a detached thread when main() exits?
A rule of thumb would be not to detach threads from main, but signal thread pool that app is ending and join all thread. Or do as is answered in What happens to a detached thread when main() exits?
I want to create an event loop class that will run on it's own thread, support adding of tasks as std::functions and execute them.
For this, I am using the SafeQueue from here: https://stackoverflow.com/a/16075550/1069662
class EventLoop
{
public:
typedef std::function<void()> Task;
EventLoop(){ stop=false; }
void add_task(Task t) { queue.enqueue(t); }
void start();
void stop() { stop = true; }
private:
SafeQueue<Task> queue;
bool stop;
};
void EventLoop::start()
{
while (!stop) {
Task t = queue.dequeue(); // Blocking call
if (!stop) {
t();
}
}
cout << "Exit Loop";
}
Then, you would use it like this:
EventLoop loop;
std::thread t(&EventLoop::start, &loop);
loop.add_task(myTask);
// do smth else
loop.stop();
t.join();
My question is: how to stop gracefully the thread ?
Here stop cannot exit the loop because of the blocking queue call.
Queue up a 'poison pill' stop task. That unblocks the queue wait and either directly requests the thread to clean up and exit or allows the consumer thread to check a 'stop' boolean.
That's assuming you need to stop the threads/task at all before the app terminates. I usually try to not do that, if I can get away with it.
An alternative approach: just queue up a task that throws an exception. A few changes to your code:
class EventLoop {
// ...
class stopexception {};
// ...
void stop()
{
add_task(
// Boring function that throws a stopexception
);
}
};
void EventLoop::start()
{
try {
while (1)
{
Task t = queue.dequeue(); // Blocking call
t();
}
} catch (const stopexception &e)
{
cout << "Exit Loop";
}
}
An alternative that doesn't use exceptions, for those who are allergic to them, would be to redefine Task as a function that takes an EventLoop reference as its sole parameter, and stop() queues up a task that sets the flag that breaks out of the main loop.