考虑一个具有标准异步接口(interface)的操作:
std::future<void> op();
在内部,
op
需要执行(可变)数量的异步操作才能完成;这些操作的数量是有限的,但没有限制,并且取决于先前异步操作的结果。这是一个(坏的)尝试:
/* An object of this class will store the shared execution state in the members;
* the asynchronous op is its member. */
class shared
{
private:
// shared state
private:
// Actually does some operation (asynchronously).
void do_op()
{
...
// Might need to launch more ops.
if(...)
launch_next_ops();
}
public:
// Launches next ops
void launch_next_ops()
{
...
std::async(&shared::do_op, this);
}
}
std::future<void> op()
{
shared s;
s.launch_next_ops();
// Return some future of s used for the entire operation.
...
// s destructed - delayed BOOM!
};
当然,问题在于
s
超出范围,因此以后的方法将不起作用。要对此进行修改,以下是更改:
class shared : public std::enable_shared_from_this<shared>
{
private:
/* The member now takes a shared pointer to itself; hopefully
* this will keep it alive. */
void do_op(std::shared_ptr<shared> p); // [*]
void launch_next_ops()
{
...
std::async(&shared::do_op, this, shared_from_this());
}
}
std::future<void> op()
{
std::shared_ptr<shared> s{new shared{}};
s->launch_next_ops();
...
};
(除了对象使用指向自身的共享指针调用其方法的怪异之外,问题出在标记为
[*]
的行上。 .编译器(正确地)警告它是一个未使用的变量。当然,有可能以某种方式欺骗它,但这是否表明存在根本问题?编译器是否有可能优化参数并留下死对象的方法?整个方案有更好的替代方案吗?我发现生成的代码不是最直观的。
最佳答案
不,编译器不会优化参数。事实上,这无关紧要,因为生命周期延长来自 shared_from_this()
被衰减复制( [thread.decaycopy] )绑定(bind)到调用 std::async
的结果中( [futures.async] /3)。
如果您想避免未使用参数的警告,只需将其保留为未命名;对未使用的参数发出警告的编译器不会对未使用的未命名参数发出警告。
另一种方法是制作 do_op
static
,这意味着你必须使用它的 shared_ptr
争论;这也解决了 this
之间的重复问题。和 shared_from_this
.由于这相当麻烦,您可能希望使用 lambda 来转换 shared_from_this
到 this
指针:
std::async([](std::shared_ptr<shared> const& self){ self->do_op(); }, shared_from_this());
如果您可以使用 C++14 初始化捕获,这将变得更加简单:
std::async([self = shared_from_this()]{ self->do_op(); });
关于multithreading - 动态分配的实现类 std::async-ing 其成员,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30660636/