https://github.com/mguludag/synchronized_value
A modern C++ thread-safe value wrapper with flexible locking strategies and convenient RAII guards.
https://github.com/mguludag/synchronized_value
cpp cpp11 cpp17 cpp20 thread-safety thread-synchronization
Last synced: 10 days ago
JSON representation
A modern C++ thread-safe value wrapper with flexible locking strategies and convenient RAII guards.
- Host: GitHub
- URL: https://github.com/mguludag/synchronized_value
- Owner: mguludag
- License: mit
- Created: 2025-09-23T21:19:38.000Z (14 days ago)
- Default Branch: main
- Last Pushed: 2025-09-26T21:12:32.000Z (11 days ago)
- Last Synced: 2025-09-26T21:19:03.731Z (11 days ago)
- Topics: cpp, cpp11, cpp17, cpp20, thread-safety, thread-synchronization
- Language: C++
- Homepage:
- Size: 48.8 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# mgutility::thread::synchronized_value
A modern C++ thread-safe value wrapper with flexible locking strategies and convenient RAII guards.
## Features
- Encapsulates any value type `T` with internal mutex synchronization.
- Supports customizable lock policies to use `std::unique_lock`, `std::shared_lock`, or user-defined lock types.
- Provides read and write lock guards with transparent pointer-like and dereference semantics.
- Automatically select read or write locks based on constness. (const -> read_lock, non-const -> write_lock)
- Callable interface supporting thread-safe access with lambdas.
- Customizable operator support for wrapped values via specialization of `operators` template.
- Safe simultaneous locking of multiple `synchronized_value` instances without deadlock.## C++ Version Compatibility
- Compatible with **C++11** as a minimum.
- If compiled with **C++17** or later, additional features such as `std::shared_mutex`, `std::shared_lock` are automatically enabled.## [Usage](https://godbolt.org/z/E147Tbx54)
```c++
#include
#include
#include
#includeint main() {
mgutility::thread::synchronized_value sv(42);// Read access
sv([](const int& val) {
std::cout << "Value is " << val << "\n";
});// Write access
sv([](int& val) {
val = 100;
});// Classic lock guard style
{
auto guard = sv.synchronize(/* [optional] additional args for guard object like std::adopt_lock_t{} etc. */);
std::cout << "Read with lock: " << *guard << "\n";
guard = 50; // assign new value directly (same as *guard = 50)
}
}
```## Customization Points
### Specializing `lock_policy`
You can customize which lock types are used for reading and writing by specializing the `lock_policy` for your own mutex-like types. This allows transparent use of shared mutexes, custom spinlocks, or other synchronization primitives.
Example - specialize for a custom shared mutex:
```c++
#includestruct MySharedMutex {
void lock() { /* exclusive lock implementation */ }
void unlock() { /* exclusive unlock */ }
void lock_shared() { /* shared lock */ }
void unlock_shared() { /* shared unlock */ }
};template <>
struct mgutility::thread::lock_policy {
using read_lock = std::shared_lock;
using write_lock = std::unique_lock;
};int main() {
mgutility::thread::synchronized_value sv(42);}
```
### Specializing `operators`
The `operators` template provides default equality and inequality operators that operate on the wrapped reference of type `T`. Users can specialize or inherit from this template to add or override operators for custom or complex types.
Example specialization for `std::filesystem::path` demonstrating custom comparison and path concatenation:
```c++
#include
#include
#includetemplate <>
class mgutility::thread::operators : public ref_wrapper {
public:
using ref_wrapper::value;explicit operators(std::filesystem::path& p) noexcept
: ref_wrapper(p) {}auto operator==(const std::filesystem::path& rhs) const -> bool {
return std::filesystem::equivalent(value(), rhs);
}auto operator!=(const std::filesystem::path& rhs) const -> bool {
return !(*this == rhs);
}auto operator/(const std::filesystem::path& rhs) const -> std::filesystem::path {
return value() / rhs;
}auto operator/=(const std::filesystem::path& rhs) -> std::filesystem::path& {
return (value() /= rhs);
}friend auto operator<<(std::ostream& os, operators& val) -> std::ostream&
{
return os << val.value();
}
};int main() {
mgutility::thread::synchronized_value sv("/usr/local");{
auto&& path = sv.synchronize();
path /= "bin";
std::cout << "bin folder: " << path << "\n"; // uses operator<< from user defined specialization
}// or...
mgutility::thread::synchronized_value sv_path("/usr/local");
std::cout << "bin folder: " << (*sv_path /= "bin") << "\n";
// or use operator() with lambda
}
```## Related Libraries and work
* [Boost synchronized_value](https://www.boost.org/doc/libs/latest/doc/html/thread/sds.html)
* [CsLibGuarded](https://github.com/copperspice/cs_libguarded)
* [Folly Synchronized](https://github.com/facebook/folly/blob/main/folly/docs/Synchronized.md)
* C++ proposals [P0290R4](https://wg21.link/P0290R4) and [N4033](https://wg21.link/N4033).## License
MIT License, see the [LICENSE](LICENSE) file.
## Contribution
Contributions, bug reports, and feature requests are welcome! Feel free to check the issues page.
---