gpt4 book ai didi

c++ - 用于基于任务的并行性的通用 c++11 函数包装器

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:16:04 24 4
gpt4 key购买 nike

我正在实现一个工作窃取算法,并正在编写一个通用函数包装器,它将 promise 作为包装器模板的可变参数之一。我想使用这些函数包装器创建任务,并让每个节点使用 promise 与依赖节点进行通信。每个节点都维护一个依赖节点和 promise / future 的列表。每个节点都可以通过检查是否已设置所有 future 来运行。 promises 可以根据函数包装器正在返回不同对象的工作而有所不同。如果可以将单个算法分解为单独的操作,例如读取消息和解码消息、对对象执行检查、返回所有检查的结果,则这些操作中的每一个都将返回不同的 promise (对象、 bool 值、结果)。

C++ Concurrency in Action 这本书有一个函数包装器实现,但是它不处理这个用例。在其他在线引用资料中,我看到了对像 std::promise 这样的 promise 的硬编码引用,它只是一种类型。

有人可以建议我如何编写包装器来实现以下目标......

void add(int a, int b, std::promise<int>&& prms)
{
int res = a + b;
try {
prms.set_value(res);
}
catch(...)
{
prms.set_exception(std::current_exception());
}
}

int main()
{
std::promise<int> prms;
std::future<int> fut = prms.get_future();
FunctionWrapper myFunctor(a, 10, 20, std::move(prms));

// add the functor to the queue and it will be retrieved by a thread
// that executes the task. since i have the future, i can pass it to the
// dependent worknode
}

我尝试编写如下代码......但在让它工作时遇到了困难。

#ifndef FUNCTIONWRAPPER_HPP
#define FUNCTIONWRAPPER_HPP

template<typename F, typename R, typename... Args>
class FunctionWrapper
{
class implbase
{
public:
virtual ~implbase();
virtual R execute(Args...)=0;
};

class impl : public implbase
{
public:
impl(F&& f) : func(std::move(f)) {}
virtual R execute(Args... args) { return func(args...); }

private:
F func;
};

std::shared_ptr<impl> internalFunc;

public:
FunctionWrapper(F&& f) : internalFunc(0)
{
internalFunc = new impl<F, R, Args...>(f);
}

FunctionWrapper(const FunctionWrapper& other)
: internalFunc(std::move(other.internalFunc))
{}

~FunctionWrapper()
{
if(internalFunc)
delete internalFunc;
}

R operator()(Args... args)
{
return internalFunc->execute(args...);
}

void swap(FunctionWrapper& other)
{
impl<R, Args...>* tmp = internalFunc;
internalFunc = other.internalFunc;
other.internalFunc = tmp;
}

FunctionWrapper& operator=(const FunctionWrapper& other)
{
FunctionWrapper(other).swap(*this);
return *this;
}

FunctionWrapper& operator=(const F& f)
{
FunctionWrapper(f).swap(*this);
return *this;
}
};

#endif // FUNCTIONWRAPPER_HPP

最佳答案

C++11 有一个包装器可以做到这一点!它叫做packaged_task .

它的作用是包装一个可调用对象(函数对象、lambda、函数指针、绑定(bind)表达式等...)并通过匹配的 get_future() 方法为您提供 future 传入函数的返回类型。

考虑以下示例:

#include <thread>
#include <future>
#include <functional>
#include <iostream>

using namespace std;

int add(int a, int b)
{
return a + b;
}

int main()
{
// Create a std::packaged_task and grab the future out of it.
packaged_task<int()> myTask(bind(add, 10, 20));
future<int> myFuture = myTask.get_future();

// Here, is where you would queue up the task in your example.
// I'll launch it on another thread just to demonstrate how.
thread myThread(std::move(myTask));
myThread.detach();

// myFuture.get() will block until the task completes.
// ...or throw if the task throws an exception.
cout << "The result is: " << myFuture.get() << endl;
return 0;
}

如您所见,我们没有传递 promise,而是依靠 packaged_task 来创建 promise 并为我们提供 future 。

此外,使用绑定(bind)表达式使我们能够有效地将参数传递给任务以保留直到它被调用。

使用 packaged_task 还会将 future 推送异常的负担交给 packaged_task。这样,您的函数就不需要调用 set_exception()。他们只需要返回或抛出。

关于c++ - 用于基于任务的并行性的通用 c++11 函数包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13998059/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com