我有一个简单的线程池。它获取任务并使用循环法在线程之间分配它们。 任务看起来像这样
using TaskFn = void (*)(void*);
struct Task {
TaskFn fn;
void* args;
};
只有两个指针:指向接受
void*
的函数和指向参数本身。线程池调用 Task::fn
并传递 Task::args
。一切都运转良好。
但是我想为整个事情编写一个类型化包装器。所以我可以这样写:
Task some_task = MakeTask([](int a, int b){
// Task body
}, 123, 456);
我不需要关闭来工作。我写的代码无法编译:
template <typename Function, typename ... Args>
void DoCall(Function f, std::tuple<Args...>* args) {
auto callable = [args, f](){
std::apply(f, *args);
};
callable();
}
template <typename Function, typename ... Args>
Task MakeTask(Function f, Args ... args) {
Task task;
std::tuple<Args...>* args_on_heap = new std::tuple<Args...>(args...);
task.args = (void*) args_on_heap;
TaskFn fn = [](void* ptr){
// The problem here is that I can’t pass `f` here without creating a closure.
// But if I create a closure, the signature will be different.
// In theory, everything that is needed is known at the compilation stage.
// But how to curb the compiler?
DoCall<Function, Args...>(f, (std::tuple<Args...>*) ptr);
};
task.fn = fn;
return task;
// P.S I know that args_on_heap leaks.
}
所以,问题:
提前谢谢您:)
捕获 lambda 可以存储在 std::function 中,并且为了防止参数泄漏,您应该使用 std::shared_ptr。
#include <functional>
#include <memory>
struct Task {
std::function<void(void*)> fn;
std::shared_ptr<void> args;
};
template <typename Function, typename ... Args>
void DoCall(Function f, std::tuple<Args...>* args) {
auto callable = [args, f](){
std::apply(f, *args);
};
callable();
}
template <typename Function, typename ... Args>
Task MakeTask(Function f, Args ... args) {
Task task;
task.args = std::make_shared<std::tuple<Args...>>(args...);
task.fn = [f](void* ptr){
DoCall<Function, Args...>(f, (std::tuple<Args...>*) ptr);
};
return task;
}