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();
}
}
CodePudding user response:
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 correspondingfree
asynchronously (e.g. viastd::async
), orindirectly 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.
CodePudding user response:
You'll need two classes: AcquirableResource
and AcquiredResource
. You first create the AcquirableResource
instance, which outlasts close (might even be used to reopen); then you have AcquiredResource
from AcquirableResource
which is the opened resource. This is fully RAII.
// define the AcquirableResource and AcquiredResource
int main() {
AcquirableResource ares("filename.txt");
// ... your code here ...
{
auto res(ares); // open
if (!res) { /* error handler */ }
// ... your code here ...
// res goes out of scope, signals ares
// ares closes file (can be async)
}
// ares is still valid here
// ... your code here ...
// ares goes out of scope, dtor close in sync
}