如何处理 RAII 中的资源等待

How to deal with Resource-waiting in RAII

我是 C++ 新手,目前正在学习 RAII(资源获取即初始化)模式。 我很好奇人们将如何处理他们需要等待的资源。

在Java中,可能要做的事情是:

MyClass obj = new MyClass();
new Thread(
    () -> obj.initialize(); // resource acquisition
).start()

...

if (obj.initialized()) {
    // Use object
}

换句话说,我们可以在后台进行耗时的资源获取。

我们如何在 C++ 中使用 RAII 做到这一点?或者这是 RAII 的限制?

RAII 在可以获取尚未准备好使用的对象时解决反模式。特别是,您的 Java 代码存在相同的反模式 - MyClass 的用户很容易在构造对象后立即忘记 运行 initialize 方法。

当需要进行复杂的初始化时,执行 RAII 的最简单方法是通过工厂方法。将可能不安全的构造函数设为私有并公开一个 public 静态函数,该函数将为您构造 初始化对象。特别是,如果您想 运行 同时进行初始化,没有什么可以阻止您将该工厂方法的 return 类型转换为 std::future 或类似的类型。

关键要点是 RAII 的目的 - 必须不可能获取未初始化的资源。通过将唯一方法获取到始终初始化资源的函数中,您将获得 RAII。

RAII 表示资源由某个对象定义。理想情况下,该对象的构造函数获取资源,而析构函数释放它。在对象有效期间,您可以使用对象与资源进行交互。

如果资源 "needs to be waited on",那么根据 RAII 的规则,这意味着您还没有代表该资源的对象 。相反,您有一个对象代表将来可用的资源。

这就是 C++ 调用此类型的原因 std::future。它是一个模板,参数是您正在等待其创建的对象的类型。

从概念上讲,future 只是一种将对象(或异常)从生成它的代码(可能是异步的)转发给接收者的方法。

现在给出你的例子,我们需要从 MyClass 中删除 initialize 并使其成为一个函数 returns a MyClass 实例。它可以是 MyClass 的静态成员,也可以只是一个命名空间作用域的函数。

因此代码基本上如下所示:

auto future = std::async(initialize);

...

if(future.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
{
  MyClass resource = future.get(); //The `future` is now empty. Any exceptions will be thrown here.

  //use resource
}