From fec33596d6aabb2f17365f91b70fb9c850427626 Mon Sep 17 00:00:00 2001 From: bergmann Date: Sat, 16 Nov 2019 16:03:45 +0100 Subject: [PATCH] * Implemented locked type (used the get locked access to any resource) * Moved files from 'threading' to 'synchronization' --- include/cppcore.h | 2 +- .../{threading.h => synchronization.h} | 1 + .../cancellation_token.h | 0 .../cancellation_token.inl | 0 include/cppcore/synchronization/locked.h | 125 ++++++++++++++++++ include/cppcore/synchronization/locked.inl | 123 +++++++++++++++++ .../cancellation_token_tests.cpp | 2 +- test/cppcore/synchronization/locked_tests.cpp | 37 ++++++ 8 files changed, 288 insertions(+), 2 deletions(-) rename include/cppcore/{threading.h => synchronization.h} (65%) rename include/cppcore/{threading => synchronization}/cancellation_token.h (100%) rename include/cppcore/{threading => synchronization}/cancellation_token.inl (100%) create mode 100644 include/cppcore/synchronization/locked.h create mode 100644 include/cppcore/synchronization/locked.inl rename test/cppcore/{threading => synchronization}/cancellation_token_tests.cpp (85%) create mode 100644 test/cppcore/synchronization/locked_tests.cpp diff --git a/include/cppcore.h b/include/cppcore.h index a4343e5..0afeb63 100644 --- a/include/cppcore.h +++ b/include/cppcore.h @@ -4,4 +4,4 @@ #include "cppcore/defines.h" #include "cppcore/misc.h" #include "cppcore/platform.h" -#include "cppcore/threading.h" +#include "cppcore/synchronization.h" diff --git a/include/cppcore/threading.h b/include/cppcore/synchronization.h similarity index 65% rename from include/cppcore/threading.h rename to include/cppcore/synchronization.h index 8c29883..8024467 100644 --- a/include/cppcore/threading.h +++ b/include/cppcore/synchronization.h @@ -1,3 +1,4 @@ #pragma once #include "threading/cancellation_token.h" +#include "threading/locked.h" diff --git a/include/cppcore/threading/cancellation_token.h b/include/cppcore/synchronization/cancellation_token.h similarity index 100% rename from include/cppcore/threading/cancellation_token.h rename to include/cppcore/synchronization/cancellation_token.h diff --git a/include/cppcore/threading/cancellation_token.inl b/include/cppcore/synchronization/cancellation_token.inl similarity index 100% rename from include/cppcore/threading/cancellation_token.inl rename to include/cppcore/synchronization/cancellation_token.inl diff --git a/include/cppcore/synchronization/locked.h b/include/cppcore/synchronization/locked.h new file mode 100644 index 0000000..3380eb7 --- /dev/null +++ b/include/cppcore/synchronization/locked.h @@ -0,0 +1,125 @@ +#pragma once + +#include +#include +#include + +namespace cppcore +{ + + template< + typename T_value, + typename T_lock = std::mutex> + struct locked + { + public: + template + struct locked_ref; + + using value_type = T_value; + using lock_type = T_lock; + using guard_type = std::unique_lock; + using locked_ref_type = locked_ref; + using locked_ref_ptr_u = std::unique_ptr; + using locked_const_ref_type = locked_ref; + using locked_const_ref_ptr_u = std::unique_ptr; + + template + struct locked_ref + { + public: + using value_type = T_locked_value; + using reference_type = value_type&; + using pointer_type = value_type*; + + private: + guard_type _guard; + + public: + value_type& value; + + public: + /** + * @brief Constructor. + */ + inline locked_ref( + guard_type&& p_guard, + value_type& p_value); + + inline pointer_type operator->(); + inline reference_type operator*(); + }; + + private: + mutable lock_type _lock; + value_type _value; + + public: + /** + * @brief Constructor. + */ + template + inline locked(X_args&&... p_args); + + public: + /** + * @brief Lock the resource stored in this object and return the locked reference. + */ + inline locked_ref_type lock(); + + /** + * @brief Try to lock the resource stored in this object and return the locked reference. + */ + inline locked_ref_ptr_u try_lock(); + + /** + * @brief Try to lock the resource stored in this object and return the locked reference. + */ + template + inline locked_ref_ptr_u try_lock_for( + const std::chrono::duration& timeout); + + /** + * @brief Try to lock the resource stored in this object and return the locked reference. + */ + template + inline locked_ref_ptr_u try_lock_until( + const std::chrono::time_point& timeout); + + public: + /** + * @brief Lock the resource stored in this object and return the locked reference. + */ + inline locked_const_ref_type lock() const; + + /** + * @brief Try to lock the resource stored in this object and return the locked reference. + */ + inline locked_const_ref_ptr_u try_lock() const; + + /** + * @brief Try to lock the resource stored in this object and return the locked reference. + */ + template + inline locked_const_ref_ptr_u try_lock_for( + const std::chrono::duration& timeout) const; + + /** + * @brief Try to lock the resource stored in this object and return the locked reference. + */ + template + inline locked_const_ref_ptr_u try_lock_until( + const std::chrono::time_point& timeout) const; + }; + + /** + * @brief Construct a locked object with the passed arguments. + */ + template< + typename T_value, + typename... X_args> + inline locked make_locked(X_args&&... p_args); + +} + +#include "locked.inl" diff --git a/include/cppcore/synchronization/locked.inl b/include/cppcore/synchronization/locked.inl new file mode 100644 index 0000000..9ddeb8b --- /dev/null +++ b/include/cppcore/synchronization/locked.inl @@ -0,0 +1,123 @@ +#pragma once + +#include "locked.h" + +namespace cppcore +{ + /* locked_ref */ + + template + template + locked::locked_ref::locked_ref( + guard_type&& p_guard, + value_type& p_value) + : _guard(std::move(p_guard)) + , value (p_value) + { } + + template + template + typename locked::template locked_ref::pointer_type + locked::locked_ref::operator->() + { return &value; } + + template + template + typename locked::template locked_ref::reference_type + locked::locked_ref::operator*() + { return value; } + + /* locked */ + + template + template + locked::locked(X_args&&... p_args) + : _value(std::forward(p_args)...) + { } + + template + typename locked::locked_ref_type + locked::lock() + { return locked_ref_type(guard_type(_lock), _value); } + + template + typename locked::locked_ref_ptr_u + locked::try_lock() + { + guard_type guard(_lock, std::defer_lock); + return guard.try_lock() + ? std::make_unique(std::move(guard), _value) + : nullptr; + } + + template + template + typename locked::locked_ref_ptr_u + locked::try_lock_for( + const std::chrono::duration& timeout) + { + guard_type guard(_lock, std::defer_lock); + return guard.try_lock_for(timeout) + ? std::make_unique(std::move(guard), _value) + : nullptr; + } + + template + template + typename locked::locked_ref_ptr_u + locked::try_lock_until( + const std::chrono::time_point& timeout) + { + guard_type guard(_lock, std::defer_lock); + return guard.try_lock_until(timeout) + ? std::make_unique(std::move(guard), _value) + : nullptr; + } + + template + typename locked::locked_const_ref_type + locked::lock() const + { return locked_const_ref_type(guard_type(_lock), _value); } + + template + typename locked::locked_const_ref_ptr_u + locked::try_lock() const + { + guard_type guard(_lock, std::defer_lock); + return guard.try_lock() + ? std::make_unique(std::move(guard), _value) + : nullptr; + } + + template + template + typename locked::locked_const_ref_ptr_u + locked::try_lock_for( + const std::chrono::duration& timeout) const + { + guard_type guard(_lock, std::defer_lock); + return guard.try_lock_for(timeout) + ? std::make_unique(std::move(guard), _value) + : nullptr; + } + + template + template + typename locked::locked_const_ref_ptr_u + locked::try_lock_until( + const std::chrono::time_point& timeout) const + { + guard_type guard(_lock, std::defer_lock); + return guard.try_lock_until(timeout) + ? std::make_unique(std::move(guard), _value) + : nullptr; + } + + /* misc */ + + template< + typename T_value, + typename... X_args> + locked make_locked(X_args&&... p_args) + { return locked(std::forward(p_args)...); } +} diff --git a/test/cppcore/threading/cancellation_token_tests.cpp b/test/cppcore/synchronization/cancellation_token_tests.cpp similarity index 85% rename from test/cppcore/threading/cancellation_token_tests.cpp rename to test/cppcore/synchronization/cancellation_token_tests.cpp index 4cb198e..e004c65 100644 --- a/test/cppcore/threading/cancellation_token_tests.cpp +++ b/test/cppcore/synchronization/cancellation_token_tests.cpp @@ -1,5 +1,5 @@ #include -#include +#include using namespace ::cppcore; diff --git a/test/cppcore/synchronization/locked_tests.cpp b/test/cppcore/synchronization/locked_tests.cpp new file mode 100644 index 0000000..cf13d1d --- /dev/null +++ b/test/cppcore/synchronization/locked_tests.cpp @@ -0,0 +1,37 @@ +#include +#include + +using namespace ::cppcore; + +TEST(locked_tests, simple) +{ + auto l = make_locked(); + + { + auto ref = l.lock(); + *ref = 5; + } + + { + auto ref = l.lock(); + EXPECT_EQ(5, *ref); + } +} + +TEST(locked_tests, try_lock) +{ + auto l = make_locked(); + + { + auto ref = l.lock(); + *ref = 5; + + EXPECT_FALSE(l.try_lock()); + } + + { + auto ref = l.try_lock(); + ASSERT_TRUE(ref); + EXPECT_EQ (5, **ref); + } +}