|
| | RWLEnvelope (RWLEnvelope< ContainerType > &&src) noexcept |
| | RWLEnvelope (ContainerType &&src) |
| template<typename T> |
| | RWLEnvelope (std::initializer_list< T > init) |
| void | reassign (ContainerType &&src) |
| | RWLEnvelope (const ContainerType &arg) |
| RWLEnvelope & | operator= (RWLEnvelope const &)=delete |
| | Copy assignment operator (deleted).
|
| template<typename Callback, typename... Args> |
| auto | observe (Callback cbf, Args &&... args) const |
| template<typename Callback, typename... Args> |
| auto | mutate (Callback cbf, Args &&... args) |
| ContainerType | snapshot () const |
| std::tuple< const ContainerType &, RLock > | readLock () |
| std::tuple< ContainerType &, RWLock > | writeLock () |
template<typename ContainerType>
requires std::copy_constructible<ContainerType>
class siddiqsoft::RWLEnvelope< ContainerType >
Thread-safe envelope wrapper using reader-writer locks.
- Template Parameters
-
| ContainerType | Type for your object which is to be "enveloped" |
RWLEnvelope provides a simple, convenient envelope-access model for thread-safe access to objects using reader-writer locks. It wraps a type ContainerType with std::shared_mutex to enable safe concurrent read and exclusive write access patterns.
Thread Safety Guarantees
- Multiple Readers: Multiple threads can call observe() or readLock() concurrently
- Exclusive Writer: Only one thread can call mutate() or writeLock() at a time
- Reader-Writer Exclusion: No readers can access while a writer is active, and vice versa
- Exception Safe: Move constructor is noexcept; mutate() includes exception handling
Usage Patterns
Callback-based Access
bool exists = cache.observe([](const auto& m) noexcept {
return m.count("key") > 0;
});
cache.mutate([](auto& m) noexcept {
m["key"] = 42;
});
Thread-safe envelope wrapper using reader-writer locks.
Direct Lock Access
if (auto const& [map, lock] = data.readLock(); lock) {
auto it = map.find("key");
if (it != map.end()) {
std::cout << it->second << std::endl;
}
}
Snapshot for External Processing
std::vector<int> copy = data.snapshot();
std::sort(copy.begin(), copy.end());
Callbacks with Additional Arguments
std::string searchKey = "target";
bool found = data.observe(
[](const auto& m, const std::string& key) noexcept {
return m.find(key) != m.end();
},
searchKey
);
Performance Considerations
- Keep callbacks and lock scopes as short as possible
- Avoid I/O operations (file, network) within locks
- Use snapshot() for expensive post-processing
- Use observe() or readLock() to avoid copying
- Direct callbacks eliminate std::function overhead
Limitations
- Copy assignment is deleted; use move semantics
- Default constructor requires T to be default-constructible
- Mutex is not shared when moving envelopes
- No recursive locking (will deadlock)
- All callbacks must be marked noexcept
- Examples
- /opt/azure-agent/_work/15/s/include/siddiqsoft/RWLEnvelope.hpp.
Definition at line 180 of file RWLEnvelope.hpp.