facebookexperimental / facebookexperimental/libunifex
RAII in my async_mutex? It's more likely than you think.
- Dominant language
- C++
- Stars
- 1.7k
- Forks
- 210
- PR merge metrics
- No merged PRs in 30d
Description
Right now, usage patterns of async_mutex violate RAII in any case whatsoever, as locking the mutex (the "resource acquisition" part) is an async operation, and so cannot be done as part of a constructor (the "is initialization" part).
I think there will be no objections to this requiring a fix, so how would we do that?
I propose changing the signature of `async_lock` from `sender_of async_lock()` to `sender_of async_lock()`, where the asynchronously returned `unique_lock_like` object will unlock the mutex in it's destructor. This does mend the problem, as now initialization of this `unique_lock_like` object is precisely the same as acquiring the mutex.
The intention is for this new signature to be used as follows:
```
let_value(mtx.async_lock(), [](auto&) {
// safely work with the protected objects
};
```
A further expansion of this idea would be a rust-like `Mtx` class, which internally stores a `T`, and returns a reference to `T` from it's `async_lock` method. Although we won't ever have rust-like safety guarantees without borrowing, such a class would still prove to be useful in my opinion for a lot of use cases, simplifying the code and explicitly syntactically linking the protected object with the protecting synchronization primitive. With this, on could write code like
```
let_value(data_storage.async_lock(), [](auto& storage ) {
return do_other_async_work(storage->at("key"));
};
```
Which I think is more structured and less error-prone than the current status quo,
```
let_value(mtx.async_lock(), [&data_storage, &mtx]() {
return then(do_other_async_work(data_storage->at("key")),
[&mtx]() { mtx.unlock(); });
};
```
Contributor guide
Assessment
This issue has not been assessed yet.