wrapping std::packaged_task inside a custom class - c++

I'm trying to wrap std::packaged_task inside another class in order to be used together with a task scheduler.
At the moment I got it all working except std::future support. To get std::future support I figured out I need to use std::packaged_task for the get_future() function that it provides.
I've been trying whole day all sorts of ways to get this to work, but I seem to be unable to properly declare and initialise the packaged_task using the return value from a std::bind. I have tried to decipher the implementations of all the related libstdc++ functions such as std::async, std::future, std::thread etc but with no luck.
The following code is the implementation of both the not working version and the working one. To get it to work uncomment the two /* --- WORKS*/ and comment the other related line.
#include <vector>
#include <deque>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <future>
#include <iostream>
#include <chrono>
#include <functional>
#include <windows.h>
class task
{
private:
struct task_implementation_base
{
virtual void execute() = 0;
};
template <class callable>
struct task_implementation : public task_implementation_base
{
task_implementation(callable&& f) : /*m_task(std::forward<callable>(f)) WORKS*/m_task(f) { }
void execute() { m_task(); }
//callable m_task; // WORKS
std::packaged_task<typename result_of<callable>::type> m_task;
};
template <class callable>
std::shared_ptr<task_implementation<callable>> make_routine(callable&& f)
{
return std::make_shared<task_implementation<callable>>(std::forward<callable>(f));
}
public:
template <class callable, class... arguments>
task(callable&& f, arguments&&... args) : m_function(make_routine(std::bind(std::forward<callable>(f), std::forward<arguments>(args)...))) {}
void operator()() { run(); }
void run() { m_function->execute(); }
private:
std::shared_ptr<task_implementation_base> m_function;
};
int testint(int i)
{
std::cout << "test6" << " :: ran from thread " << std::this_thread::get_id() << "\n";
fflush(stdout);
return i+100;
}
void test(const char* text)
{
std::cout << text << " :: ran from thread " << std::this_thread::get_id() << "\n";
fflush(stdout);
}
class testclass
{
public:
void print1() { test("test3"); }
void print2() { test("test4"); }
void print3(const char* text) { test(text); }
};
int main()
{
testclass testclass1;
testclass* testclass2 = new testclass;
task test1(test, "test1");
task test2([]() { test("test2"); });
task test3(&testclass::print1, &testclass1);
task test4(&testclass::print2, &*testclass2);
task test5(&testclass::print3, &*testclass2, "test5");
task test6(&testint, 1);
test1();
test2();
test3();
test4();
test5();
test6();
Sleep(2000);
return 0;
}
I'm thinking the problem is typename result_of<callable>::type. I'm guessing it doesn't properly evaluates to the return type of the callable function.
I'm using c++ (Built by MinGW-builds project) 4.8.0 20121225 (experimental) on a Windows 8 64bit. I'm suspecting the errors are irrelevant since I guess I'm just simply trying to get this work the wrong way but here is a pastebin for the errors anyway: errors

std::packaged_task not only takes the result type of the invoked function as a template argument but also the types of the arguments you are passing to the to be invoked function.
You can define them as follows:
// somewhere
int foo(bool, int);
// somewhere else
std::packaged_task<int(bool, int)> p(foo);
To fix your code you need to add two empty parenthesis pairs. What I explained above also applies to std::result_of.
std::packaged_task<typename std::result_of<callable()>::type()> m_task;

It is only response to main topic question. "How to implement"
Example short implementation:
template <typename Signature> /// <---- 1
class Task;
template <typename Res, typename... ArgTypes>
class Task<Res(ArgTypes...)> /// <---- 2
{
public:
template <typename Function>
explicit Task(Function&& callback)
: _task{std::forward<Function>(callback)}
{ }
void execute(ArgTypes... args) noexcept(false)
{
//...
_task(std::forward<ArgTypes>(args)...);
}
private:
std::packaged_task<Res(ArgTypes...)> _task;
};
Not sure why step 1 & 2 are required but I did the same as in lib implementation. Maybe someone could extend this response.

Related

std::function & std::forward with variadic templates

Recently I was reading about variadic templates and based on an example I've seen online I was trying to implement a basic event-system. So far it seems to work fine but I was trying to go a step further and allow N number of arguments to be passed to an event handler function / callback, unfortunately the build error I'm getting is the following and I'm not sure what I'm doing wrong. I looked into similar source codes but still cant figure out what's the issue.
D:\Development\lab\c-cpp\EventEmitter3\src\main.cpp:30:68: error: parameter packs not expanded with '...':
return std::any_cast<std::function<R(Args)>>(eventCallback)(std::forward<Args>(args)...);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
D:\Development\lab\c-cpp\EventEmitter3\src\main.cpp:30:68: note: 'Args'
Build finished with error(s).
Here is what I have so far, if you remove the ... the event system works fine for the 2 registered events in main.
#include <any>
#include <string>
#include <iostream>
#include <functional>
#include <unordered_map>
class EventEmitter
{
private:
std::unordered_map<std::string, std::any> events;
public:
EventEmitter() {}
void on(const std::string &eventName, const std::any &eventCallback)
{
events[eventName] = eventCallback;
}
template <typename R>
R emit(const std::string &eventName)
{
const std::any &eventCallback = events[eventName];
return std::any_cast<std::function<R(void)>>(eventCallback)();
}
template <typename R, typename... Args>
R emit(const std::string &eventName, Args &&...args)
{
const std::any &eventCallback = events[eventName];
return std::any_cast<std::function<R(Args)>>(eventCallback)(std::forward<Args>(args)...);
}
virtual ~EventEmitter() {}
};
int fun1()
{
std::cout << "fun1" << std::endl;
return 1;
}
double fun2(int i)
{
std::cout << "fun2" << std::endl;
return double(i);
}
double fun3(int x, int y)
{
std::cout << "fun3" << std::endl;
return double(x + y);
}
int main(int argc, char *argv[])
{
EventEmitter e;
e.on("fun1", std::function<int(void)>(fun1));
e.on("fun2", std::function<double(int)>(fun2));
e.emit<int>("fun1");
e.emit<double, int>("fun2", 1);
// Variadic would have been handy right here I guess?
// e.on("fun3", std::function<double(int, int)>(fun3));
// e.emit<double, int>("fun3", 1, 2);
return 0;
}
How can I fix this?
Well, you need to expand it.
return std::any_cast<std::function<R(Args...)>>(eventCallback)(std::forward<Args>(args)...);
^^^^^^^

RenderClass with Multithread-Support, push functioncalls to vector for invoking on another thread

I'm trying to make a RenderClass where 1 function gets called from a Thread, which calculates everything and pushes the function calls to a vector while the other Thread calls a function of RenderClass which then calls every function that got pushed on the vector, is this even possible? also my code doesn't give me intellisense errors in vs just some weird C3867 error that doesn't make sense in my opinion when trying to compile.
I already tried playing around with the template function
like removing the RenderClass::*function to
template<typename Function, typename ...ARGS>
void QueueRenderFunction(Function *function, ARGS... args)
but can't get it to work.
here the whole testprogram I tested this on...
#include <Windows.h>
#include <iostream>
#include <functional>
#include <string>
#include <vector>
#include <mutex>
class Vector3 {
float x, y, z;
};
class RenderClass
{
public:
template<typename Function, typename ...ARGS>
void QueueRenderFunction(Function RenderClass::*function, ARGS... args)
{
_RenderList.push_back(std::forward<Function>(function, args...));
}
void CallRenderFunctions()
{
std::lock_guard<std::recursive_mutex> l(renderlist_mtx);
for (auto&& Function : RenderList)
Function();
}
//just as examplecode
void DRAWCIRCLE(Vector3 Position, float Range) {
std::cout << Range << std::endl;
}
void DRAWSTRING(Vector3 Position, std::string String) {
std::cout << String << std::endl;
}
void QueueDrawings() {
//begin new Renderlist
_RenderList.clear();
//some drawing calcs
//some Position
Vector3 Position;
QueueRenderFunction(DRAWCIRCLE, Position, 100.f);
QueueRenderFunction(DRAWSTRING, Position,"Name");
std::lock_guard<std::recursive_mutex> l(renderlist_mtx);
RenderList = _RenderList;
}
private:
std::recursive_mutex renderlist_mtx;
std::vector<std::function<void()>> RenderList;
std::vector<std::function<void()>> _RenderList;
};
RenderClass* Renderer = new RenderClass();
void Render() {
while (true)
{
Renderer->CallRenderFunctions();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int main() {
std::thread RenderThread(Render);
while (true)
{
Renderer->QueueDrawings();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
return 0;
}
like said I get for example this error:
Severity Code Description Project File Line Suppression State
Error C3867 'RenderClass::DRAWCIRCLE': non-standard syntax; use '&' to create a pointer to member
and trying to &DRAWCIRCLE just then gives me
Error C2276 '&': illegal operation on bound member function expression
that's what makes me say it doesn't make sense in my opinion
Your problem is that you have a std::vector<std::function<void()>>, which is fine, but you need to add some augments. std::bind is your friend.
This code should do the trick.
template<typename Function, typename ...ARGS>
void QueueRenderFunction(Function function, ARGS... args)
{
_RenderList.push_back(std::bind(function, args...));
}
You probably also want to define the function you put into the render list as free from functions and pass what would have been this as argument.
As a side note, you probably want to use RenderList.swap(_RenderList); to reduce copying.

std::lock_guard with variadic templates

[It is not necessary to follow the links to understand the question].
I combined the implementation of the singleton pattern in this answer, together with the synchronized file writing of this other answer.
Then I wanted to see if the interface of SynchronizedFile could provide a variadic templated write method, but I couldn't figure out how to properly combine this with the std::lock_guard.
Below is a non-working example. In this case it doesn't work because (I think) the two threads manage to pump stuff into the buffer i_buf in a non-synchronized way, resulting in a garbled LOGFILE.txt.
If I put the std::lock_guard inside the general template of write then the program doesn't halt.
#include <iostream>
#include <mutex>
#include <sstream>
#include <fstream>
#include <string>
#include <memory>
#include <thread>
static const int N_LOOP_LENGTH{10};
// This class manages a log file and provides write method(s)
// that allow passing a variable number of parameters of different
// types to be written to the file in a line and separated by commas.
class SynchronizedFile {
public:
static SynchronizedFile& getInstance()
{
static SynchronizedFile instance;
return instance;
}
private:
std::ostringstream i_buf;
std::ofstream i_fout;
std::mutex _writerMutex;
SynchronizedFile () {
i_fout.open("LOGFILE.txt", std::ofstream::out);
}
public:
SynchronizedFile(SynchronizedFile const&) = delete;
void operator=(SynchronizedFile const&) = delete;
template<typename First, typename... Rest>
void write(First param1, Rest...param)
{
i_buf << param1 << ", ";
write(param...);
}
void write()
{
std::lock_guard<std::mutex> lock(_writerMutex);
i_fout << i_buf.str() << std::endl;
i_buf.str("");
i_buf.clear();
}
};
// This is just some class that is using the SynchronizedFile class
// to write stuff to the log file.
class Writer {
public:
Writer (SynchronizedFile& sf, const std::string& prefix)
: syncedFile(sf), prefix(prefix) {}
void someFunctionThatWritesToFile () {
syncedFile.write(prefix, "AAAAA", 4343, "BBBBB", 0.2345435, "GGGGGG");
}
private:
SynchronizedFile& syncedFile;
std::string prefix;
};
void thread_method()
{
SynchronizedFile &my_file1 = SynchronizedFile::getInstance();
Writer writer1(my_file1, "Writer 1:");
for (int i = 0; i < N_LOOP_LENGTH; ++ i)
writer1.someFunctionThatWritesToFile();
}
int main()
{
std::thread t(thread_method);
SynchronizedFile &my_file2 = SynchronizedFile::getInstance();
Writer writer2(my_file2, "Writer 2:");
for (int i = 0; i < N_LOOP_LENGTH; ++i)
writer2.someFunctionThatWritesToFile();
t.join();
std::cout << "Done" << std::endl;
return 0;
}
How could I successfully combine these three ideas?
The program deadlocks because write calls itself recursively while still holding the lock.
Either use a std::recursive_mutex or release the lock after writing your data out but before calling write.
E: Unlocking doesn't do the job, I didn't think this through...
E: Or lock once and defer to another private method to do the write.
template<typename... Args>
void write(Args&&... args)
{
std::unique_lock<std::mutex> lock(_writerMutex);
_write(std::forward<Args>(args)...);
}
template<typename First, typename... Rest>
void _write(First&& param1, Rest&&... param) // private method
{
i_buf << std::forward<First>(param1) << ", ";
_write(std::forward<Rest>(param)...);
}
void _write()
{
i_fout << i_buf.str() << std::endl;
i_buf.clear();
}

Understanding bind

I have a bit of trouble understanding a std::bind call.
In the following example:
#include <functional>
#include <iostream>
#include <memory>
class Notifier
{
public:
Notifier(std::function<void(Notifier&)> on_notify)
:on_notify_(on_notify)
{ }
void notify()
{
if (on_notify_)
on_notify_(*this);
}
std::function<void(Notifier&)> on_notify_;
};
struct Manager
{
Manager()
{
n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this));
}
void trigger()
{
std::cout << "notified" << std::endl;
}
std::unique_ptr<Notifier> n_;
};
int main()
{
Manager s;
s.n_->notify();
}
I don't understand how on_notify_(*this); calls back the functor with a Notifier& parameter, but the functor created by bind doesn't specify it.
The calls result correctly to the void notify() method, but I don't understand what exactly will be the functor created by bind to result in this.
If I were to write a lambda instead, I would need to specify the parameter, otherwise it would compile.
What kind of operation does bind here behind my back? :-)
std::bind basically ignores the invalid given argument according to this.
If some of the arguments that are supplied in the call to g() are not matched by any placeholders stored in g, the unused arguments are evaluated and discarded.
It might surprise you that when even more absurd arguments are provided, the binded functor can still successfully reach Manager::trigger() as follows:
#include <functional>
#include <iostream>
#include <memory>
// Some classes that have nothing to do with on_notify_
class AAA {};
class BBB {};
class Notifier
{
public:
Notifier(std::function<void(AAA&, BBB&)> on_notify)
:on_notify_(on_notify)
{ }
void notify()
{
if (on_notify_)
{
// Arguments not matching.
AAA a{};
BBB b{};
// Invoke with them.
on_notify_(a, b);
}
}
std::function<void(AAA&, BBB&)> on_notify_;
};
struct Manager
{
Manager()
{
n_ = std::make_unique<Notifier>(std::bind(&Manager::trigger, this));
}
void trigger()
{
std::cout << "it's also notified!" << std::endl;
}
std::unique_ptr<Notifier> n_;
};
int main()
{
Manager s;
s.n_->notify();
}
Live demo is here.

How to manage parallel and sequential version code with least duplication?

I have written a sequential version of a program, and want to parallel it with thrust-CUDA. Notice that these two versions of code are very similar (like std::vector, thrust::device_vector, thrust::host_vector), I wonder how can I manage these codes such that user can choose either version at run time while avoiding duplication?
Thanks.
You could template your code on the type of vector you are using and write explicit specialisations to perform operations specific to the type.
#include <iostream>
#include <vector>
struct other_vector { };
template<typename T> struct SpecificImplementation;
template<> struct SpecificImplementation<other_vector>
{
void SpecificWork() { std::cout << "other_vector specific work\n"; }
};
template<> struct SpecificImplementation<std::vector<int>>
{
void SpecificWork() { std::cout << "std::vector<int> specific work\n"; }
};
template<typename T>
struct GeneralImplementation : public SpecificImplementation<T>
{
void CommonWork() { std::cout << "common work\n"; }
void Run() { this->SpecificWork(); CommonWork(); }
};
int main()
{
GeneralImplementation<other_vector> i1;
i1.Run();
GeneralImplementation<std::vector<int>> i2;
i2.Run();
//GeneralImplementation<int> i3; <-- will not compile without implementation
return 0;
}
Live Example