What I want to do is design a class that can execute a function asynchronously. I need warp it in member function, because I want to know whether it complete or not.
The basic design is the following:
struct SelectionAsynMission
{
template<typename Function, typename...Args>
void start(Function && f, Args&&...a)
{
// compiler failed here
thread_.swap(thread(std::bind(&SelectionAsynMission::execute_warp<Function, Args ...>, this), f,std::forward<Args>(a)...));
//thread_.swap(std::thread(f, std::forward<Args>(a)...)); no warp work fine
thread_.detach();
}
template<typename Function, typename...Args>
void execute_warp(Function && f, Args&& ... a)
{
thread_complete_ = false;
f(std::forward<Args>(a)...);
thread_complete_ = true;
}
void join();
atomic<bool> thread_complete_; // Use atomic to tell the main thread whether it is complete.
thread thread_;
};
The Compile Error is:
error C2064: term does not evaluate to a function taking 1 arguments
So any suggestion for the design to fulfill the requirement
Or ideas about fix the compile error would be helpful.
Thank you for your help, I was stupid enough to forget the basic of std::bind.
Before see your comments and answers
I have tried another way to do this. I use async to warp the function, and instead the atomic, i use future status to determine whether the job complete. I wasn't sure which cost more time, read atomic or future status, but the future status seems easier.
template<class Function, class...Args>
void start(Function && f, Args&... a)
{
// start the function with async
future_node_ = std::async(std::launch::async,f,std::forward<Args&>(a)...);
}
bool iscomplete()
{
// wait for zero time to get status.
auto status = future_node_.wait_for(std::chrono::nanoseconds(0));
// determine whether the job is done
return status == std::future_status::ready;
}
Well, you have kind of a skeleton of something usable. But the error is pretty obvious if you look where the error is coming from:
std::thread(std::bind(member_fn, this), fn, args...)
You're trying to pass arguments to a function object returned from a std::bind that doesn't take any arguments.
What you want to do is pretty hard using std::bind, because it requires the std::placeholders constructs _1, _2, _3, etc, etc to signal that there are _n many args to be passed. That would require some template trickery.
A better option would be to use a lambda expression; a feature of C++11, which you are probably using seeing as though you make use of std::thread which is another C++11 feature.
Here's how to do it using lambdas:
class myclass{
template<typename Func, typename ... Args>
void start(Func &&f, Args &&... args){
m_thread.swap(std::thread{
[this](Func &&f, Args &&... uargs){
this->execute_warp(std::forward<Func>(f), std::forward<Args>(uargs)...);
},
std::forward<Func>(f), std::forward<Args>(args)...
});
m_thread.detach();
}
template<typename Func, typename ... Args>
void execute_warp(Func &&f, Args &&... args){
m_thread_done = false;
f(std::forward<Args>(args)...);
m_thread_done = true;
}
void join(){
while(!m_thread_done.load(std::memory_order_relaxed)){}
}
std::atomic<bool> m_thread_done;
std::thread m_thread;
}
And I might add a way to do it using std::bind to my answer.
Related
I've been reading a tutorial by Ben Hoffman (https://benhoffman.tech/cpp/general/2018/11/13/cpp-job-system.html)
I've had a go at bashing together a version of the Job/Worker system he has, but instead of using void* for arguments then casting to a known struct, I've been trying to use variadic arguments. The idea is, a job takes in a "parent" to perform a method on, the function pointer to said method, and an Args... for the argument(s). However, I get an internal compiler error if I try to build. Here is the job class:
template <class T, typename... Args>
struct JobMemberFunc : IJob
{
JobMemberFunc(T* aParent, void (T::* f)(Args...), Args... Args)
{
parentObj = aParent;
func_ptr = f;
saved_args = ::std::make_tuple (::std::move(Args)...);
}
virtual bool invoke() override
{
if (!parentObj) { return false; }
(parentObj->*func_ptr)(::std::move(saved_args));
return true;
}
/** the object to invoke the function pointer on */
T* parentObj;
/** The function pointer to call when we invoke this function */
void (T::* func_ptr)(Args...);
::std::tuple<Args...> saved_args;
};
struct CpuJob
{
IJob* jobPtr = nullptr;
};
Then there's the AddJob method, where the internal compiler error is actually happening.
template <typename T, typename... Args>
void AddJob(T* aParent, void(T::* func_ptr)(Args...), Args... args)
{//This curly bracket is where the internal compiler error happens
CpuJob aJob = {};
JobMemberFunc<T, Args...>* jobPtr = new JobMemberFunc<T, Args...>(aParent, func_ptr,
std::forward<Args>(args)...);
aJob.jobPtr = jobPtr;
locklessReadyQueue.enqueue(aJob);
}
More than happy to be told this is a bad/wrong way of trying to do it anyway. I have thought about doing away with it and having a standardized argument list or doing something polymorphic but I really wanna make this work so I can literally ask the job system to do anything I like.
Thanks!
std::function<void()> (in combination with lambdas) already do what you're trying to do with JobMemberFunc.
void AddJob(std::function<void()>&& job)
{
locklessReadyQueue.enqueue(std::move(job));
}
With this you can submit any function call as a job.
For example, a call some_obj.some_method(some_arg) becomes:
AddJob([&] { some_obj.some_method(some_arg); });
No more ugly pointer-to-member stuff...
You can find more complete thread pooling examples here: Thread pooling in C++11
I am trying to write a performance test that can run functions with
different number of arguments.
Something like this:
// optimization.cpp
struc Command{
unkown_type fun;
} command1;
perf_test(Command exec){
unkown_type ptr = exec.fun
// start timer
ptr();
// stop timer
}
// main.cpp
user_function1(double x[], double y[]);
user_function2(double x[], double y[], int z, double A[]);
// somehow bind function
command1.exec = user_function1
perf_test(command1);
Is there somehow a way of doing this and getting good results e.g. function inlining and so on or is this simply not possible?
I know about std::function and std::bind but unfortunately std::function
has a large overhead which makes no sense for my performance measurements.
You are making this more complicated than it needs to be.
template <class Function, class ...Args>
auto perf_test(Function &&f, Args && ...args) {
// start timer
std::forward<Function>(f)(std::forward<Args>(args) ...);
// stop timer
//print or return or store time
}
To be used like
auto passed_time = perf_test(user_function1, somex, somey);
If you really must have your Command struct you can store the args in a std::tuple and then use std::apply to call the function. If you put the time measuring code around the function and then assign it to an std::function you can use the convenience of std::function without its overhead influencing your measurement. This can look something like
template <class Function, class... Args>
std::function<std::chrono::nanoseconds()> make_perf_test(Function &&f,
Args &&... args) {
return [f = std::forward<Function>(f),
args = std::make_tuple(std::forward<Args>(args)...)]() mutable {
const auto start = std::chrono::high_resolution_clock::now();
std::apply(std::forward<decltype(f)>(f), std::move(args));
return std::chrono::high_resolution_clock::now() - start;
};
}
to be used like
auto uf1 = make_perf_test(user_function1, x, y);
std::cout << "user_function1 took " << uf1().count() << "ns\n";
This gives you an easy to store type std::function<std::chrono::nanoseconds()> that type-erases the parameters and arguments away while not including that overhead in the measurement.
There is are some tweaking spot. Maybe the lambda should not be mutable so that the arguments cannot change so that you can repeat the measurement. Also due to limitations of std::function, this requires that the function and parameters are copyable.
You can use a variadic template for this.
template<typename F, typename... Args>
void invoke_func(F func, Args&&... args) {
func(std::forward<Args>(args)...);
}
You can then call that directly within your performance measuring code.
So I'm trying to create a class which has a container for functors of a different type.
This is a simplified version of it.
template<class T>
class Container
{
public:
template<typename F, typename ... ARGS>
void addTask(F && func, ARGS && ... args);
private:
std::deque<std::function<T()>> container;
//.....
};
template<class T>
template<typename F, typename ... ARGS>
T Container<T>::addTask(F && func, ARGS && ... args);
{
container.emplace_back(std::bind(f,args...));
//.....
}
There are still few problems that I cannot solve yet.
Is there a way to remove std::bind and store a different object or a pointer?
Could this be more generic? Can I somehow store functions, which return different objects, in a single container(int,void...)?
Can some of the logic for creating the tasks be executed in compile time?Something like consexpr bind.
From a comment by the OP.
There are. This is simplified. I'm using futures and a special container in the real code. It is meant to be used in a multithreading environment
This is called burying the lede.
If you are storing callables to be invoked in other threads, in the other thread you want signature void(). In this thread you want a std::future to be populated.
As for binding arguments, while a number of std functions do this for you, I find it is best to ask for callables with pre-bound arguments. They can do it outside, using std::bind or lambdas or whatever other means they choose.
So this then comes
template<class Func,
class R = std::decay_t<std::result_of_t<Func const&()>>
>
std::future< R >
addTask( Func&& func ) {
auto task = std::packaged_task<R()>(std::forward<Func>(func));
auto ret = task.get_future();
container.push_back( std::packaged_task<void()>( std::move(task) ) );
return ret;
}
std::deque< std::packaged_task<void()> > container;
throw in some mutexes and shake and bake.
Here I use std::packaged_task<void()> as a pre-written move-only type-erased container for anything with that signature. We don't use the future it can produce, which is a waste, but it is shorter than writing your own move-only invoke-once owning function object.
I personally just wrote myself a light weight move-only std::function<void()> esque class instead of using std::packaged_task<void()>, but it was probably unwise.
The future returned from addTask gets fullfilled when the packaged_task<R()> is invoked, which is invoked when the packaged_task<void()> is invoked (possibly in another thread).
Outside of the structure, callers can give you any zero-argument callable object.
99 times out of 100, a simple [some_arg]{ some_code; } or even []{ some_code; } works. In complex cases they can mess around with std::bind or C++14 improvements with more complex lambdas.
Putting the storing of the arguments into addTask mixes the responsibility of the thread-task-queue with messing with arguments.
In fact, I'd write a thread-safe queue separately from my thread-pool, and have the thread-pool use it:
template<class T>
struct thread_safe_queue;
struct thread_pool {
thread_safe_queue< std::packaged_task<void()> > queue;
// etc
};
In C++17, a replacement for your bind looks like:
[
func = std::forward<Func>(func),
args = std::make_tuple( std::forward<Args>(args)... )
]() mutable {
std::apply( func, std::move(args) );
}
In C++14 you can write notstd::apply pretty easy. Move-into-lambda requires C++14, so if you need to efficiently move arguments you need std bind or a manual function object in C++11.
I will argue that placing the argument binding strongly in the domain of the code using the thread pool is best.
That also permits the thread pool to do things like pass the tasks optional extra arguments, like "cancellation tokens" or the like.
std::bind came from boost::bind, which was necessary before we had lambdas.
Unfortunately std::bind made it into the standard at the same time as lambdas, so it was immediately almost irrelevant.
In c++14 and beyond you can capture the function and args in a variadic lambda:
template<class T>
template<typename F, typename ... ARGS>
T Container<T>::addTask(F && func, ARGS && ... args)
{
container.emplace_back( [func = std::forward<F>(func),
args...]
() mutable // make mutable if you want to move the args in to func
{
return func(std::move(args)...);
});
//.....
}
You don't quite get perfect forwarding this way. There is a copy implicit in the capture of args...
This solved in c++17
template<class T>
template<typename F, typename ... ARGS>
T Container<T>::addTask(F && func, ARGS && ... args)
{
container.emplace_back( [func = std::forward<F>(func),
args = std::make_tuple(std::forward<ARGS>(args)...) ]
() mutable // make mutable if you want to move the args in to func
{
return std::apply(func, std::move(args));
});
//.....
}
I have a vector defined like std::vector<std::function<void()>> functions and to store an item I use a function in this way:
template <typename Fun, typename Instance, typename ... Args>
void AddFunction(std::string name, Fun&& fun, Instance* instance, Args&& ... args)
{
/*something is going on here*/
functions.push_back(std::bind(fun, instance, std::forward<Args>(args)...));
/*something is going on here*/
}
The problem is that sometimes the function passed to std::bind can return some kind of value. I thought about using lambdas and I tried something like this
template <typename Fun, typename Instance, typename ... Args>
void AddFunction(std::string name, Fun&& fun, Instance* instance, Args&& ... args)
{
/*something is going on here*/
auto lambda = [&]() -> void
{
fun(std::forward<Args>(args)...);
};
functions.push_back(std::move(lambda));
/*something is going on here*/
}
but each time I try to use AddFunction an error message shows up saying that term does not evaluate to a function taking n arguments where n is the number of arguments that the function I pass to AddFunction takes.
Is there some workaround so that I can store items of type std::function<void()> even if the function stored returns a value?
Both
functions.push_back(std::bind(fun, instance, std::forward<Args>(args)...));
and
auto lambda = [&]() -> void
{
(instance->*fun)(std::forward<Args>(args)...);
};
functions.push_back(std::move(lambda));
work just fine with Visual Studio.
I'm trying hard for some hours and didn't manage to get this working.
I have a templated class spinlock:
template<typename T> class spinlock {
// ...
volatile T *shared_memory;
};
I'm trying to create something like this:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
But I'm trying to use a polymorphic function so that I can do this:
spinlock<int> spin;
int a = spin.exec([]() {
return 10;
});
int b = spin.exec([](int x) {
return x;
}, 10); // argument here, passed as x
// If the signature matches the given arguments to exec() plus
// the shared variable, call it
int c = spin.exec([](volatile int &shared) {
return shared;
}); // no extra arguments, shared becomes the
// variable inside the spinlock class, I need to make
// a function call that matches this as well
// Same thing, matching the signature
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}, 10); // extra argument, passed as x... should match too
// Here, there would be an error
int d = spin.exec([](volatile int &shared, int x) {
return shared + x;
}); // since no extra argument was given
Basically, I'm trying to make an exec function that accepts F(Args...) or F(volatile T &, Args...) as an argument.
But I can't manage to make automatic detection of types.
How could I accomplish that?
Firstly, this signature will not compile:
// inside spinlock class
template<typename F, typename... Ars>
std::result_of(F(Args...))
exec(F fun, Args&&... args) {
// locks the memory and then executes fun(args...)
};
The return type needs to be
typename std::result_of<F(Args...)>::type
If your compiler implements N3436 then this function will not participate in overload resolution when fun(args...) is not a valid expression, but that is not required in C++11 and not implemented by many compilers yet. You will need to implement your own SFINAE check to prevent result_of giving an error when fun(args...) is not valid, or rewrite it without result_of
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(std::forward<Args>(args)...))
{
// locks the memory and then executes fun(args...)
}
Then you can overload it for functions that need the additional parameter passed in:
template<typename F, typename... Args>
auto
exec(F fun, Args&&... args) -> decltype(fun(*this->shared_memory, std::forward<Args>(args)...))
{
// locks the memory and then executes fun(*shared_memory, args...)
}
When fun(std::forward<Args>(args)...) is not valid the first overload will not participate in overload resolution. When fun(*this->shared_memory, std::forward<Args>(args)...) is not valid the second overload will not participate in overload resolution. If neither is valid the call will be ill-formed, if both are valid the call will be ambiguous.