析构函数和异步任务
Destructors and asynchronous tasks
我有一个类,它在构造函数中使用std::async
调用异步任务以加载其内容。(我希望异步加载对象)
代码如下:
void loadObject(Object* object)
{
// ... load object
}
Object::Object():
{
auto future = std::async(std::launch::async, loadObject, this);
}
我在我的主线程上有几个创建和删除这些对象的实例,它们可以随时被删除,甚至在加载完成之前。
我想知道当对象仍在另一个线程上处理时,将其销毁是否有危险。如果对象被破坏,我该如何停止线程?
EDIT:由于存在错误,std::future
析构函数不会用我正在使用的VS2013编译器阻止我的代码。
正如MikeMB已经提到的,在加载完成之前,构造函数不会完成。检查这个问题以了解如何克服这个问题:我可以在不等待未来限制的情况下使用std::async吗?
我想知道当对象仍在另一个线程上处理时,销毁它是否有危险。
删除后访问对象的内存肯定是危险的。行为将是不明确的。
如果对象被破坏,我如何停止线程?
我建议您首先注意的是,确保对象在被要使用它的东西指向时不会被破坏。
一种方法是使用表示已完成加载的成员标志,该标志在异步任务中更新并在析构函数中检查,并将访问与条件变量同步。这将允许析构函数阻塞,直到异步任务完成。
一旦您设法防止对象被销毁,您就可以使用另一个同步成员标志来表示对象正在被销毁,并跳过加载(如果已设置)。这会增加同步开销,但如果加载成本很高,这可能是值得的。
另一种避免阻塞析构函数的方法是将std::shared_ptr
传递给异步任务,并要求所有Object
实例都由一个共享指针拥有。这种限制可能不是很理想,您需要继承std::enable_shared_from_this
才能在构造函数中获得共享指针。
您的代码中没有任何异步发生,因为构造函数会阻塞,直到loadObject()
返回(std::async
返回的future的析构函数隐式联接)。
如果没有,这将取决于您如何编写代码(尤其是析构函数),但最有可能的是,您的代码会产生未定义的行为。
是当对象仍在另一个线程上处理时,将其销毁是危险的
实际上,您可以根据需求和期望的行为来实施许多策略。
我会在这里实现某种皮条策略,这意味着所有实际数据都将存储在对象所持有的指针中。您将把所有数据加载到数据指针对象,并以原子方式将其存储在公共对象中。
施工结束时,技术性物体应完全收缩并准备使用。在您的情况下,数据指针对象可能仍然无法使用。你应该让你的类正确地处理这种状态。
所以我们开始了:
class Object
{
std::shared_ptr<Object_data> d;
Object::Object():
d(std::make_shared<Object_data>())
{
some_futures_matser.add_future(std::async(std::launch::async, loadObject, d));
}
}
然后,在数据对象中制作原子标志,表示加载已完成,对象已准备好使用。
class Object_data
{
// ...
std::atomic<bool> loaded {false};
};
loadObject(std::shared_ptr<Object_data> d)
{
/// some load code here
d->loaded = true;
}
每次通过loaded
标志访问对象(使用线程安全的方式)时,都必须检查对象是否受到约束
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 有没有任务栏API可以立即应用注册表更改
- 如何创建线程序列以按照启动顺序执行任务?
- C++一个线程如何正确通信其任务已完成?
- 如何在C++中实现带有packaged_task的异步等待循环?
- Qt异步调用:如何在异步调用完成任务后运行一些东西
- 使异步任务休眠
- 如何在执行异步后台任务的C++中构造对象
- C 异步与OpenMP任务
- 取消一个c++11异步任务
- 析构函数和异步任务
- C++REST SDK:异步任务与C++11多线程
- 异步用于基于任务的并发
- 每个任务一个异步线程
- 在WinRT中从异步任务lambda更新UI
- UWP/WinRT:如何在模型中的异步操作完成后执行UI任务
- C++异步任务。包括"Future"麻烦
- 触发异步任务并忘记它的C++ 11 种方法是什么?
- 异常处理,WinRT c++并发异步任务
- 等待多个异步任务完成