* Moved files from 'threading' to 'synchronization'master
| @@ -4,4 +4,4 @@ | |||
| #include "cppcore/defines.h" | |||
| #include "cppcore/misc.h" | |||
| #include "cppcore/platform.h" | |||
| #include "cppcore/threading.h" | |||
| #include "cppcore/synchronization.h" | |||
| @@ -1,3 +1,4 @@ | |||
| #pragma once | |||
| #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 <cppcore/threading/cancellation_token.h> | |||
| #include <cppcore/synchronization/cancellation_token.h> | |||
| 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); | |||
| } | |||
| } | |||