template event class take any arg - c++

I have a simple event class, everything works fine with it.
Im trying to add a template class that i can pass arguments to and then read it when wait finishes.
At the moment i have it working with struct only as i need to set the arg to 0 if im not using it.
Is there a better/easier way to do this so i can pass any type of argument to it?
class Event
{
public:
Event() : _signalled(false) {}
virtual void notify()
{
std::unique_lock<std::mutex> lock(_mutex);
_signalled = true;
_condvar.notify_one();
}
virtual void wait()
{
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock, [&] { return _signalled; });
_signalled = false;
}
void stop()
{
std::unique_lock<std::mutex> lock(_mutex);
_signalled = false;
}
private:
std::mutex _mutex;
std::condition_variable _condvar;
bool _signalled;
};
template <class T>
class ArgEvent : public Event
{
public:
void notify()
{
Event::notify();
this->arg = { 0 };
}
void notify(T arg)
{
Event::notify();
this->arg = arg;
}
T getArg()
{
return this->arg;
}
void wait()
{
Event::wait();
}
void wait(T& arg)
{
Event::wait();
arg = this->arg;
}
private:
T arg;
};

Boost.Optional allows the implementation to work without c++17.
https://www.boost.org/doc/libs/1_67_0/libs/optional/doc/html/index.html

Related

Parameter pack unpacking returns default object in thread pool

I am currently tasked with writing a generic thread pool, having multiple worker threads and one scheduling thread in c++. To support running any kind of function within one pool I used variadic functions and parameter packs, in which I have little experience.
My thread pool and worker class looks like this
template<typename R, typename ...A>
class Worker {
public:
// starts thread that runs during lifetime of worker object
Worker() : thread_([this] {
while (!stopped) {
// run task that worker has been set to and remove it thereafter
if (task_ != NULL) {
idle = false;
task_(std::get<A>(args_)...);
task_ = NULL;
}
idle = true;
}
}) { }
~Worker() {
stop();
}
void stop() {
stopped = true;
thread_.join();
}
bool idling() {
return idle;
}
void set_work(std::function<R(A...)> task, std::tuple<A...> args) {
task_ = task;
args_ = args;
}
private:
std::thread thread_;
std::function<R(A...)> task_;
std::tuple<A...> args_;
bool idle = false;
bool stopped = false;
};
template<typename R, typename ...A>
class ThreadPool {
public:
// pool runs scheduling thread which assigns queued tasks to idling workers
ThreadPool(size_t num_workers) : workers(num_workers), num_workers_(num_workers), runner([this, num_workers] {
while(!stopped) {
for (size_t i = 0; i < num_workers; i++) {
if (workers[i].idling() && !q.empty()) {
workers[i].set_work(q.front().first, q.front().second);
q.pop();
}
}
}
}) { }
void add_task(std::function<R(A...)> task, A... args) {
q.push({task, std::make_tuple(args...)});
}
size_t tasks_left() {
return q.size();
}
size_t workers_idling() {
size_t n = 0;
for (size_t i = 0; i < num_workers_; i++) {
if (workers[i].idling()) n++;
}
return n;
}
void stop() {
for (size_t i = 0; i < num_workers_; i++) {
workers[i].stop();
}
stopped = true;
runner.join();
}
private:
std::vector<Worker<R, A...>> workers;
std::queue<std::pair<std::function<R(A...)>, std::tuple<A...>>> q;
std::thread runner;
bool stopped = false;
size_t num_workers_;
};
The first hurdle I encountered was that I was not able to use references as variadic types, so I used the whole object.
But any class not specifying a default constructor, throws the following error https://pastebin.com/ye6enTD3.
Accordingly for any other class which does, the member variables are not consistently the same as the object I passed to the worker.
I would appreciate your help on this topic.
I would start out with something like this.
Note stopping a threadpool that still has work needs design decissions.
And yes you will need mutexes and condition variables to make everything work and synchronize. A good threadpool implementation is not trivial.
#include <future>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <iostream>
class task_itf
{
public:
virtual void operator()() = 0;
};
template<typename retval_t>
struct task_t final :
public task_itf
{
public:
explicit task_t(std::function<retval_t()> fn) :
m_task{ fn }
{
}
void operator()() override
{
m_task();
}
auto future()
{
return m_task.get_future();
}
private:
std::packaged_task<retval_t ()> m_task;
};
class threadpool_t
{
public:
threadpool_t() :
m_running{ true }
{
}
template<typename fn_t>
auto schedule(fn_t fn) -> std::future<decltype(fn())>
{
using retval_t = decltype(fn());
auto task = std::make_shared<task_t<retval_t>>(fn);
{
std::scoped_lock<std::mutex> lock{ m_mtx };
m_queue.push(task);
}
m_queued.notify_one();
return task->future();
}
private:
// .. todo let the threads pickup queue entries one by one.
// if a thread is finished with a task and there are entries
// in the queue it can immediately pickup the next.
// otherwise wait for signal on m_cv;
std::mutex m_mtx;
std::condition_variable m_queued;
bool m_running;
// shared_ptr, because we hand over task to another thread later
std::queue<std::shared_ptr<task_itf>> m_queue;
};
int main()
{
threadpool_t pool;
pool.schedule([] {std::cout << "Hello world"; });
}

Thread wrapper with custom destruct function

Let me start with a short example
class A
{
public:
A() :
thread_([this] {
std::unique_lock<std::mutex> lk(mtx_);
cv_.wait(lk, [this] { return quit_; });
})
{
throw std::exception();
}
~A()
{
quit_ = true;
cv_.notify_one();
thread_.join();
}
private:
bool quit_ = false;
std::mutex mtx_;
std::condition_variable cv_;
std::thread thread_;
};
int main()
{
try { A a; }
catch (...) {}
// Does not reach this point
}
Because an exception is thrown in the constructor, the members are being destructed in reverse order.
the thread_ member is still joinable so terminate is being called.
It is pretty straightforward to write a thread wrapper class with a customizable destructor.
For example, something like that:
class ThreadWrapper
{
public:
ThreadWrapper(std::function<void(std::thread & t)> onDestruct, std::thread&& thread) :
onDestruct_(onDestruct),
thread_(std::move(thread))
{
}
~ThreadWrapper()
{
onDestruct_(thread_);
}
private:
std::function<void(std::thread & t)> onDestruct_;
std::thread thread_;
};
class B
{
public:
B() :
thread_(
[this](std::thread& t) {
quit_ = true;
cv_.notify_one();
t.join();
},
std::thread([this] {
std::unique_lock<std::mutex> lk(mtx_);
cv_.wait(lk, [this] { return quit_; });
}))
{
throw std::exception();
}
private:
bool quit_ = false;
std::mutex mtx_;
std::condition_variable cv_;
ThreadWrapper thread_;
};
However, I was surprised not to find something like that in the boost library.
The closest thing I found is the scoped_thread which lets you pass a specific action as a template parameter.
Am I missing something?

EventTask with std::condition_variable

Im trying to make a EventTask that calls a function passed in a loop.
I need it to wait to start then mark it as finished.
My problem is i dont know how to receive the arguments from my wait function to pass to the function that is called
As you can see the problem is in my taskFunc _event.wait should set the arguments to pass onto the function.
class Event
{
public:
Event() : _signalled(false) {}
virtual inline void notify(){
std::unique_lock<std::mutex> lock(_mutex);
_signalled = true;
_condvar.notify_one();
}
virtual inline void wait(){
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock, [&] { return _signalled; });
_signalled = false;
stop();
}
virtual inline void stop(){
std::unique_lock<std::mutex> lock(_mutex);
_signalled = false;
}
private:
std::mutex _mutex;
std::condition_variable _condvar;
bool _signalled;
};
template <class T>
class EventArg : public Event
{
public:
virtual inline void notify(T arg){
Event::notify();
this->arg = arg;
}
virtual inline void wait(T& arg){
Event::wait();
arg = this->arg;
}
private:
T arg;
};
template<class... Args>
class EventTask
{
public:
EventTask(std::function<void(Args...)> func) : m_Function(func), m_Run(true), m_thread(&taskFunc, this) {}
void notify(Args&& ...Params) {
_Event.notify(std::forward<Args>(Params)...); }
void wait() {
_EventFinished.wait(); }
void stop() {
m_stop = true;
_Event.stop();
}
private:
void taskFunc()
{
void* pArg = nullptr;
while (m_Run){
_Event.wait(pArg);
m_Function(std::forward<Args>(Params)...);
_EventFinished.notify();
}
}
private:
std::function<void(Args...)> m_Function;
bool m_Run;
std::thread m_thread;
EventArg<Args...> _Event;
Event _EventFinished;
};
Try this:
#include <iostream>
#include <functional>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <tuple>
template<class... Args>
class EventTask
{
public:
EventTask(std::function<void(Args...)> func) : m_Function(func), m_Run(true) {
m_thread = std::thread{ [=]() {
taskFunc();
}};
}
~EventTask() {
stop();
m_thread.join();
}
void notify(const std::tuple<Args...> &args) {
std::unique_lock<std::mutex> lock(_mutex);
_signalled = true;
_args = args;
_condvar.notify_all();
}
void stop() {
m_Run = false;
_condvar.notify_all();
}
private:
void taskFunc()
{
std::tuple<Args...> args;
while (true){
{
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock, [&] { return m_Run && _signalled; });
if (!m_Run) break;
_signalled = false;
args = _args;
}
std::apply(m_Function, args);
//_EventFinished.notify();
}
}
private:
std::function<void(Args...)> m_Function;
std::tuple<Args...> _args;
std::mutex _mutex;
std::condition_variable _condvar;
bool _signalled = false;
//Event _EventFinished;
bool m_Run;
std::thread m_thread;
};
int main()
{
EventTask<int, int> ma{ [](int a, int b) {
}};
ma.notify({ 1, 2 });
}
What is going on here? There are two threads, "producer" thread (the one, that produces arguments for function, hence the name) and "consumer" thread (the one, that actually does the running).
"producer" thread locks mutex, copies arguments and notifies, that there is something to be done. "consumer" thread locks mutex, then waits on condition. Waiting on condition (and mutex) releases the mutex, which will be reaquired, when notification on condition variable comes. When "producer" variable sets arguments, "consumer" will awoke, reacquire the mutex (this is required, otherwise "producer" might set args twice in a row resulting a race, which is undefined behavior), once again copies arguments and releases mutex. Then it continues with calling the worker function, using it's own local copy of arguments.
Similar process goes, when you try to stop the whole thing. "producer" locks mutex, sets m_Run to false and notifies everyone. "consumer" thread awoke, notifies, that m_Run is false and breads from the loop, ending it's thread. Note, that this won't break worker function, that is already in progress - you've to wait (note the call to join in destructor) for it to finish.

How do I store stored function call with arguments and retrieve them later for callback in C++?

What I am trying to do now is to store stored function calls with arguments into a list or vector, retrieve them later, and call them.
What I've got now:
a task class:
struct basic_task
{
virtual ~basic_task()
{
}
virtual void run()
{
std::cout<<"will run basic"<<std::endl;
}
};
template<typename OBJ, typename FUNC, typename ...ARGS>
struct task: basic_task
{
OBJ obj_;
FUNC OBJ::*func_;
std::tuple<ARGS...> args_;
task(OBJ& obj, FUNC OBJ::*func, ARGS ... args) :
obj_(obj), func_(func)
{
args_ = std::make_tuple(std::forward<ARGS>(args)...);
}
virtual ~task()
{
//delete args_;
}
virtual void run()
{
std::cout<<"will run real"<<std::endl;
caller::call(obj_, func_, args_);
}
};
a task binder:
struct task_binder
{
template<typename OBJ, typename FUNC, typename ...ARGS>
static auto bind(OBJ& obj, FUNC OBJ::*func,
ARGS ... args)->task<OBJ,FUNC,ARGS...>
{
task<OBJ, FUNC, ARGS...> result
{ obj, func, args... };
return result;
}
};
And what I am trying to do now is a task_queue class, which stores instances by calling produce, and consume the task by calling consume.
class task_queue: public task_queue_if
{
public:
task_queue() :
flag_(true), cond_(mutex_)
{
}
virtual ~task_queue()
{
}
virtual void close()
{
lock_guard lock(mutex_);
flag_ = false;
cond_.broadcast();
}
virtual void produce(const basic_task& t)
{
lock_guard lock(mutex_);
bool was_empty = task_list_.empty();
task_list_.push_back(t);
if (was_empty)
{
cond_.signal();
}
}
virtual int consume()
{
lock_guard lock(mutex_);
while (task_list_.empty())
{
if (flag_ == false)
return -1;
cond_.wait();
}
basic_task tt = task_list_.front();
task_list_.pop_front();
tt.run() // won't call the stored function call
return 1;
}
private:
volatile bool flag_;
mutex_lock mutex_;
std::list<basic_task> task_list_;
condition_var cond_;
}
So my problem is the consume call will call the basic_task's run() function rather than the one in task. However, if I did not store them as type basic_task but as task, it won't compile. And if I store them as basic_task, when I want to call it, I won't know which type of task should I cast the task to, so it won't compile either. Is there a way to do it?
Thanks.

use a callback as a parameter

I have the following class:
class Timer
{
public:
Timer(){};
~Timer(){};
void timer(int);
//...
private:
//...
};
My function timer(int value) is a callback that I use in glutTimerFunc(), inside the function timer(int value) i need to use the function timer again, something like this:
void Timer::timer(int value)
{
//...
glutTimerFunc(state->getTimer(), this->timer, 0);
}
How can i do it without using a static function?
you'll need a global dispatcher that turns the int passed to glutTimerFunc into a c++ callback (member function, lambda, etc)
something like this
struct timer_dispatch
{
using callback_t = std::function<void()>;
int start_timer(int msecs, callback_t callback) {
std::unique_lock<std::mutex> lock(_mutex);
int ident = _next_id++;
_callbacks.emplace(ident, std::move(callback));
glutTimerFunc(msecs, &timer_dispatch::dispatch_timer, ident);
return ident;
}
// implement similar function for stop timer - don't forget the mutex
void stop_timer(int ident) {
std::unique_lock<std::mutex> lock(_mutex);
_callbacks.erase(ident);
}
static timer_dispatch& instance() {
static timer_dispatch _;
return _;
}
private:
// private constructor ensures use via the instance() static method;
timer_dispatch() = default;
static void dispatch_timer(int ident) {
auto self = instance();
std::unique_lock<std::mutex> lock(self._mutex);
auto it = self._callbacks.find(ident);
if (it != self._callbacks.end()) {
auto my_copy = std::move(it->second);
self._callbacks.erase(it);
lock.unlock();
my_copy();
}
}
private:
std::unordered_map<int, callback_t> _callbacks;
std::mutex _mutex;
int _next_id = 0;
};
now use like so:
// start my timer:
void myclass::start_alien() {
...
_alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
...
}
void myclass::on_alien_timeout() {
// make alien do something, possibly restart a timer...
_alien_timer_id = timer_dispatch::instance().start_timer(100, std::bind(&myclass::on_alien_timeout, this);
}
void myclass::on_alien_killed() {
timer_dispatch::instance().stop_timer(_alien_timer_id);
_alien_timer_id = -1;
}