I am trying to implement a singleton worker thread which has multiple functions which can be requested by the user. I have seen implementations for worker threads using always the same function but I need different calls. Making a worker thread for each function is incovenient because the functions will share some resources. What I did to make it work is add a queue of function calls where I simply push the function calls onto the queue and trigger the condition variable. The question now becomes whether this implementation is fine because I feel like there is a smarter way to do this.
#include <functional>
#include <queue>
#include <condition_variable>
#include <mutex>
#include <thread>
class Worker_Thread
{
private:
Worker_Thread() : th_{}, mtx_{}, q_{}
{
th_ = std::thread(&Worker_Thread::run, this);
}
std::thread th_;
std::mutex mtx_;
std::condition_variable cv_;
std::queue<std::function<void()>> q_;
void run();
void func_a(int val) {};
void func_b(float val) {};
public:
Worker_Thread(Worker_Thread const&) = delete;
void operator=(Worker_Thread const&) = delete;
static Worker_Thread& getInstance()
{
static Worker_Thread instance;
return instance;
}
void do_a(int val);
void do_b(float val);
};
void Worker_Thread::run()
{
while (true) {
std::unique_lock<std::mutex> lock(mtx_);
cv_.wait(lock);
std::function<void()> fnc = std::move(q_.front());
fnc();
q_.pop();
}
}
void Worker_Thread::do_a(int val)
{
{
// Push a function onto the queue
std::lock_guard<std::mutex> lock(mtx_);
std::function<void()> fnc = std::bind(&Worker_Thread::func_a, this, val);
q_.push(fnc);
}
// Notify the run thread to execute the queued function
cv_.notify_one();
}
void Worker_Thread::do_b(float val)
{
{
// Push a function onto the queue
std::lock_guard<std::mutex> lock(mtx_);
std::function<void()> fnc = std::bind(&Worker_Thread::func_b, this, val);
q_.push(fnc);
}
// Notify the run thread to execute the queued function
cv_.notify_one();
}
int main()
{
Worker_Thread& wth = Worker_Thread::getInstance();
wth.do_a(1);
wth.do_b(2.3);
return 0;
}