Search code examples
c++asynchronousraii

Asynchronous Destruction and RAII in C++


According to RAII when I destroy the object, its resources are deallocated. But what if the destruction of the object requires asynchronous operations? Without using RAII I can call close method of my class that will call necessary async operations and will keep shared_ptr to my object (using shared_from_this) in order to gracefully process callbacks from the async operations. After calling close I can remove my pointer to the object since I do not need it anymore - but I know that the object will not be removed until the async operations are executed.

But how can I achieve this using RAII? One of the possible solutions can be using a wrapper that when destructed will call close method of by object. But.. will it mean that my classes are RAII classes?

class Resource: public std::enable_shared_from_this<Resource> {
    int id;
public:
close() {
    some_async_functin([t = shared_from_this()] {
        std::cout << "Now I am closed " << t->id << std::endl;
    }
}



}

My solution:

class ResourceWrapper {
   std::shared_ptr<Resource> res;

   ~ResourceWrapper() {
       res.close();
   }
}

Solution

  • An object o to be asynchronously destroyed with respect to the thread, T, in which it was created cannot itself be managed via RAII, because destruction of stack-allocated objects is inherently synchronous. If o is managed via the RAII model then thread T will execute its destructor when the innermost block containing its declaration terminates, until the destructor terminates.

    If you do not want to occupy T with releasing o's resources (yet ensure that they are in fact released), then you must delegate the resource release to another thread. You can do that either

    • directly, by creating o dynamically with new and dispatching the corresponding free asynchronously (e.g. via std::async), or

    • indirectly with RAII, by having o's destructor dispatch the resource cleanup for separate asynchronous release (again, via std::async or similar).

    The latter is indirect because it requires a separate object or objects to represent the resource(s) being cleaned up until the cleanup is complete -- especially so if there are callbacks involved or similar. You face the same issue with these objects that you do with o itself. There is nothing inherently wrong with this indirection, by the way. RAII still provides the benefits it usually does.