* Moved files from 'threading' to 'synchronization'master
| @@ -4,4 +4,4 @@ | |||||
| #include "cppcore/defines.h" | #include "cppcore/defines.h" | ||||
| #include "cppcore/misc.h" | #include "cppcore/misc.h" | ||||
| #include "cppcore/platform.h" | #include "cppcore/platform.h" | ||||
| #include "cppcore/threading.h" | |||||
| #include "cppcore/synchronization.h" | |||||
| @@ -1,3 +1,4 @@ | |||||
| #pragma once | #pragma once | ||||
| #include "threading/cancellation_token.h" | #include "threading/cancellation_token.h" | ||||
| #include "threading/locked.h" | |||||
| @@ -0,0 +1,125 @@ | |||||
| #pragma once | |||||
| #include <mutex> | |||||
| #include <memory> | |||||
| #include <chrono> | |||||
| namespace cppcore | |||||
| { | |||||
| template< | |||||
| typename T_value, | |||||
| typename T_lock = std::mutex> | |||||
| struct locked | |||||
| { | |||||
| public: | |||||
| template<typename T_locked_value> | |||||
| struct locked_ref; | |||||
| using value_type = T_value; | |||||
| using lock_type = T_lock; | |||||
| using guard_type = std::unique_lock<lock_type>; | |||||
| using locked_ref_type = locked_ref<value_type>; | |||||
| using locked_ref_ptr_u = std::unique_ptr<locked_ref_type>; | |||||
| using locked_const_ref_type = locked_ref<const value_type>; | |||||
| using locked_const_ref_ptr_u = std::unique_ptr<const locked_ref_type>; | |||||
| template<typename T_locked_value> | |||||
| 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<typename... X_args> | |||||
| 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<typename X_value, typename X_ratio> | |||||
| inline locked_ref_ptr_u try_lock_for( | |||||
| const std::chrono::duration<X_value, X_ratio>& timeout); | |||||
| /** | |||||
| * @brief Try to lock the resource stored in this object and return the locked reference. | |||||
| */ | |||||
| template<typename X_clock, typename X_duration> | |||||
| inline locked_ref_ptr_u try_lock_until( | |||||
| const std::chrono::time_point<X_clock, X_duration>& 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<typename X_value, typename X_ratio> | |||||
| inline locked_const_ref_ptr_u try_lock_for( | |||||
| const std::chrono::duration<X_value, X_ratio>& timeout) const; | |||||
| /** | |||||
| * @brief Try to lock the resource stored in this object and return the locked reference. | |||||
| */ | |||||
| template<typename X_clock, typename X_duration> | |||||
| inline locked_const_ref_ptr_u try_lock_until( | |||||
| const std::chrono::time_point<X_clock, X_duration>& timeout) const; | |||||
| }; | |||||
| /** | |||||
| * @brief Construct a locked object with the passed arguments. | |||||
| */ | |||||
| template< | |||||
| typename T_value, | |||||
| typename... X_args> | |||||
| inline locked<T_value> make_locked(X_args&&... p_args); | |||||
| } | |||||
| #include "locked.inl" | |||||
| @@ -0,0 +1,123 @@ | |||||
| #pragma once | |||||
| #include "locked.h" | |||||
| namespace cppcore | |||||
| { | |||||
| /* locked_ref */ | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename T_locked_value> | |||||
| locked<T_value, T_lock>::locked_ref<T_locked_value>::locked_ref( | |||||
| guard_type&& p_guard, | |||||
| value_type& p_value) | |||||
| : _guard(std::move(p_guard)) | |||||
| , value (p_value) | |||||
| { } | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename T_locked_value> | |||||
| typename locked<T_value, T_lock>::template locked_ref<T_locked_value>::pointer_type | |||||
| locked<T_value, T_lock>::locked_ref<T_locked_value>::operator->() | |||||
| { return &value; } | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename T_locked_value> | |||||
| typename locked<T_value, T_lock>::template locked_ref<T_locked_value>::reference_type | |||||
| locked<T_value, T_lock>::locked_ref<T_locked_value>::operator*() | |||||
| { return value; } | |||||
| /* locked */ | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename... X_args> | |||||
| locked<T_value, T_lock>::locked(X_args&&... p_args) | |||||
| : _value(std::forward<X_args>(p_args)...) | |||||
| { } | |||||
| template<typename T_value, typename T_lock> | |||||
| typename locked<T_value, T_lock>::locked_ref_type | |||||
| locked<T_value, T_lock>::lock() | |||||
| { return locked_ref_type(guard_type(_lock), _value); } | |||||
| template<typename T_value, typename T_lock> | |||||
| typename locked<T_value, T_lock>::locked_ref_ptr_u | |||||
| locked<T_value, T_lock>::try_lock() | |||||
| { | |||||
| guard_type guard(_lock, std::defer_lock); | |||||
| return guard.try_lock() | |||||
| ? std::make_unique<locked_ref_type>(std::move(guard), _value) | |||||
| : nullptr; | |||||
| } | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename X_value, typename X_ratio> | |||||
| typename locked<T_value, T_lock>::locked_ref_ptr_u | |||||
| locked<T_value, T_lock>::try_lock_for( | |||||
| const std::chrono::duration<X_value, X_ratio>& timeout) | |||||
| { | |||||
| guard_type guard(_lock, std::defer_lock); | |||||
| return guard.try_lock_for(timeout) | |||||
| ? std::make_unique<locked_ref_type>(std::move(guard), _value) | |||||
| : nullptr; | |||||
| } | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename X_clock, typename X_duration> | |||||
| typename locked<T_value, T_lock>::locked_ref_ptr_u | |||||
| locked<T_value, T_lock>::try_lock_until( | |||||
| const std::chrono::time_point<X_clock, X_duration>& timeout) | |||||
| { | |||||
| guard_type guard(_lock, std::defer_lock); | |||||
| return guard.try_lock_until(timeout) | |||||
| ? std::make_unique<locked_ref_type>(std::move(guard), _value) | |||||
| : nullptr; | |||||
| } | |||||
| template<typename T_value, typename T_lock> | |||||
| typename locked<T_value, T_lock>::locked_const_ref_type | |||||
| locked<T_value, T_lock>::lock() const | |||||
| { return locked_const_ref_type(guard_type(_lock), _value); } | |||||
| template<typename T_value, typename T_lock> | |||||
| typename locked<T_value, T_lock>::locked_const_ref_ptr_u | |||||
| locked<T_value, T_lock>::try_lock() const | |||||
| { | |||||
| guard_type guard(_lock, std::defer_lock); | |||||
| return guard.try_lock() | |||||
| ? std::make_unique<locked_const_ref_type>(std::move(guard), _value) | |||||
| : nullptr; | |||||
| } | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename X_value, typename X_ratio> | |||||
| typename locked<T_value, T_lock>::locked_const_ref_ptr_u | |||||
| locked<T_value, T_lock>::try_lock_for( | |||||
| const std::chrono::duration<X_value, X_ratio>& timeout) const | |||||
| { | |||||
| guard_type guard(_lock, std::defer_lock); | |||||
| return guard.try_lock_for(timeout) | |||||
| ? std::make_unique<locked_const_ref_type>(std::move(guard), _value) | |||||
| : nullptr; | |||||
| } | |||||
| template<typename T_value, typename T_lock> | |||||
| template<typename X_clock, typename X_duration> | |||||
| typename locked<T_value, T_lock>::locked_const_ref_ptr_u | |||||
| locked<T_value, T_lock>::try_lock_until( | |||||
| const std::chrono::time_point<X_clock, X_duration>& timeout) const | |||||
| { | |||||
| guard_type guard(_lock, std::defer_lock); | |||||
| return guard.try_lock_until(timeout) | |||||
| ? std::make_unique<locked_const_ref_type>(std::move(guard), _value) | |||||
| : nullptr; | |||||
| } | |||||
| /* misc */ | |||||
| template< | |||||
| typename T_value, | |||||
| typename... X_args> | |||||
| locked<T_value> make_locked(X_args&&... p_args) | |||||
| { return locked<T_value>(std::forward<X_args>(p_args)...); } | |||||
| } | |||||
| @@ -1,5 +1,5 @@ | |||||
| #include <gtest/gtest.h> | #include <gtest/gtest.h> | ||||
| #include <cppcore/threading/cancellation_token.h> | |||||
| #include <cppcore/synchronization/cancellation_token.h> | |||||
| using namespace ::cppcore; | using namespace ::cppcore; | ||||
| @@ -0,0 +1,37 @@ | |||||
| #include <gtest/gtest.h> | |||||
| #include <cppcore/synchronization/locked.h> | |||||
| using namespace ::cppcore; | |||||
| TEST(locked_tests, simple) | |||||
| { | |||||
| auto l = make_locked<int>(); | |||||
| { | |||||
| auto ref = l.lock(); | |||||
| *ref = 5; | |||||
| } | |||||
| { | |||||
| auto ref = l.lock(); | |||||
| EXPECT_EQ(5, *ref); | |||||
| } | |||||
| } | |||||
| TEST(locked_tests, try_lock) | |||||
| { | |||||
| auto l = make_locked<int>(); | |||||
| { | |||||
| auto ref = l.lock(); | |||||
| *ref = 5; | |||||
| EXPECT_FALSE(l.try_lock()); | |||||
| } | |||||
| { | |||||
| auto ref = l.try_lock(); | |||||
| ASSERT_TRUE(ref); | |||||
| EXPECT_EQ (5, **ref); | |||||
| } | |||||
| } | |||||