【发布时间】:2017-07-14 16:41:54
【问题描述】:
我有一个需要很长时间才能运行的函数,但幸运的是它是异步运行的。我想获取此函数调用的结果并将其设置为类实例的私有变量。看起来很简单:
// Exists in some other library.
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A {
public:
void Do() {
auto lambda = [this](int val) {
// Some processing...
var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
A* a = new A;
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
问题在于将以下行添加到main,就在评论之前:
delete a;
现在当LongRunningAsync 调用回调时,它将尝试修改已删除实例(即UB)的成员变量。
有没有办法挽救这种方法?我最近了解到以下解决方案:
void LongRunningAsync(std::function<void(int)> callback) {
sleep(10);
callback(5);
}
class A : public std::enable_shared_from_this<A> {
public:
void Do() {
std::weak_ptr<A> weak = shared_from_this();
auto lambda = [weak](int val) {
auto shared = weak.lock();
if (!shared) return;
// Some processing...
shared->var_ = val;
};
LongRunningAsync(lambda);
}
private:
var_;
};
int main() {
auto a = std::make_shared<A>();
a->Do();
// Wait for LongRunningAsync to finish.
sleep(20);
return 0;
}
但这需要将 all A 变量更改为 shared_ptr。有没有一种侵入性较小的方法来完成这项工作?
【问题讨论】:
-
也许您可以让
A类拥有一个包含所有所需状态的shared_ptr? -
您不应与
sleep同步,而应与thread::join或类似的同步。 -
嗯,首先,你真的必须使用那个库吗?这个“长时间运行的异步函数”的界面对我来说看起来很笨拙。我希望异步函数返回
std::future并让客户端决定何时获取结果而不是调用回调。其次,我假设在您的示例中sleep(10); callback(5);应该在单独的线程中调用,因为目前对 LongRunningAsync 的调用实际上会阻止执行。 -
@Curious:这实际上是一个非常好的主意!让我试试……
-
@Jarod42:这只是一个例子。
标签: c++ shared-ptr race-condition undefined-behavior weak-ptr