/*============================================================================*/ /* VFLib: https://github.com/vinniefalco/VFLib Copyright (C) 2008 by Vinnie Falco This library contains portions of other open source products covered by separate licenses. Please see the corresponding source files for specific terms. VFLib is provided under the terms of The MIT License (MIT): Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*============================================================================*/ #ifndef BEAST_CONCURRENTSTATE_BEASTHEADER #define BEAST_CONCURRENTSTATE_BEASTHEADER /*============================================================================*/ /** Structured access to a shared state. This template wraps an object containing members representing state information shared between multiple threads of execution, where any thread may need to read or write as needed. Synchronized access to the concurrent state is enforced at compile time through strongly typed accessor classes. This interface design facilitates source code pattern matching to find all areas where a concurrent state is accessed. There are three types of access: - ReadAccess Allows read access to the underlying object as `const`. ReadAccess may be granted to one or more threads simultaneously. If one or more threads have ReadAccess, requests to obtain WriteAccess are blocked. - WriteAccess Allows exclusive read/write access the underlying object. A WriteAccess request blocks until all existing ReadAccess and WriteAccess requests are released. While a WriteAccess exists, requests for ReadAccess will block. - UnlockedAccess Allows read access to the underlying object without using the lock. This can be helpful when designing concurrent structures through composition. It also makes it easier to search for places in code which use unlocked access. This code example demonstrates various forms of access to a ConcurrentState: @code struct SharedData { int value1; String value2; }; typedef ConcurrentState SharedState; SharedState sharedState; void readExample () { SharedState::ReadAccess state (sharedState); print (state->value1); // read access print (state->value2); // read access state->value1 = 42; // write disallowed: compile error } void writeExample () { SharedState::WriteAccess state (sharedState); state->value2 = "Label"; // write access } @endcode Forwarding constructors with up to eight parameters are provided. This lets you write constructors into the underlying data object. For example: @code struct SharedData { explicit SharedData (int numSlots) { m_array.reserve (numSlots); } std::vector m_array; }; // Construct SharedData with one parameter ConcurrentState sharedState (16); @endcode @param Object The type of object to encapsulate. @warning Recursive calls are not supported. It is generally not possible for a thread of execution to acquire write access while it already has read access. Such an attempt will result in undefined behavior. Calling into unknown code while holding a lock can cause deadlock. See @ref CallQueue::queue(). @ingroup beast_concurrent */ template class ConcurrentState : Uncopyable { public: class ReadAccess; class WriteAccess; class UnlockedAccess; /** Create a concurrent state. Up to 8 parameters can be specified in the constructor. These parameters are forwarded to the corresponding constructor in Object. If no constructor in Object matches the parameter list, a compile error is generated. */ /** @{ */ ConcurrentState () { } template explicit ConcurrentState (T1 t1) : m_obj (t1) { } template ConcurrentState (T1 t1, T2 t2) : m_obj (t1, t2) { } template ConcurrentState (T1 t1, T2 t2, T3 t3) : m_obj (t1, t2, t3) { } template ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4) : m_obj (t1, t2, t3, t4) { } template ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) : m_obj (t1, t2, t3, t4, t5) { } template ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) : m_obj (t1, t2, t3, t4, t5, t6) { } template ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) : m_obj (t1, t2, t3, t4, t5, t6, t7) { } template ConcurrentState (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) : m_obj (t1, t2, t3, t4, t5, t6, t7, t8) { } /** @} */ private: typedef ReadWriteMutex ReadWriteMutexType; Object m_obj; ReadWriteMutexType m_mutex; }; //------------------------------------------------------------------------------ /** Unlocked access to a ConcurrentState. Use sparingly. */ template class ConcurrentState ::UnlockedAccess : Uncopyable { public: explicit UnlockedAccess (ConcurrentState const& state) : m_state (state) { } Object const& getObject () const { return m_state.m_obj; } Object const& operator* () const { return getObject (); } Object const* operator-> () const { return &getObject (); } private: ConcurrentState const& m_state; }; //------------------------------------------------------------------------------ /** Read only access to a ConcurrentState */ template class ConcurrentState ::ReadAccess : Uncopyable { public: /** Create a ReadAccess from the specified ConcurrentState */ explicit ReadAccess (ConcurrentState const volatile& state) : m_state (const_cast (state)) , m_lock (m_state.m_mutex) { } /** Obtain a read only reference to Object */ Object const& getObject () const { return m_state.m_obj; } /** Obtain a read only reference to Object */ Object const& operator* () const { return getObject (); } /** Obtain a read only smart pointer to Object */ Object const* operator-> () const { return &getObject (); } private: ConcurrentState const& m_state; ReadWriteMutexType::ScopedReadLockType m_lock; }; //------------------------------------------------------------------------------ /** Read/write access to a ConcurrentState */ template class ConcurrentState ::WriteAccess : Uncopyable { public: explicit WriteAccess (ConcurrentState& state) : m_state (state) , m_lock (m_state.m_mutex) { } /** Obtain a read only reference to Object */ Object const* getObject () const { return m_state.m_obj; } /** Obtain a read only reference to Object */ Object const& operator* () const { return getObject (); } /** Obtain a read only smart pointer to Object */ Object const* operator-> () const { return &getObject (); } /** Obtain a read/write pointer to Object */ Object& getObject () { return m_state.m_obj; } /** Obtain a read/write reference to Object */ Object& operator* () { return getObject (); } /** Obtain a read/write smart pointer to Object */ Object* operator-> () { return &getObject (); } private: ConcurrentState& m_state; ReadWriteMutexType::ScopedWriteLockType m_lock; }; #endif