Add some thread classes and fix SharedData with a simple mutex adapter

This commit is contained in:
Vinnie Falco
2013-09-20 02:36:47 -07:00
parent 755ab36f0d
commit 9534516b42
17 changed files with 574 additions and 332 deletions

View File

@@ -85,11 +85,17 @@
<ClInclude Include="..\..\beast\Net.h" /> <ClInclude Include="..\..\beast\Net.h" />
<ClInclude Include="..\..\beast\net\IPEndpoint.h" /> <ClInclude Include="..\..\beast\net\IPEndpoint.h" />
<ClInclude Include="..\..\beast\StaticAssert.h" /> <ClInclude Include="..\..\beast\StaticAssert.h" />
<ClInclude Include="..\..\beast\Thread.h" />
<ClInclude Include="..\..\beast\thread\LockGuard.h" />
<ClInclude Include="..\..\beast\thread\SharedData.h" />
<ClInclude Include="..\..\beast\thread\SharedLockGuard.h" />
<ClInclude Include="..\..\beast\thread\SharedMutexAdapter.h" />
<ClInclude Include="..\..\beast\TypeTraits.h" /> <ClInclude Include="..\..\beast\TypeTraits.h" />
<ClInclude Include="..\..\beast\type_traits\IntegralConstant.h" /> <ClInclude Include="..\..\beast\type_traits\IntegralConstant.h" />
<ClInclude Include="..\..\beast\type_traits\IsIntegral.h" /> <ClInclude Include="..\..\beast\type_traits\IsIntegral.h" />
<ClInclude Include="..\..\beast\type_traits\IsSigned.h" /> <ClInclude Include="..\..\beast\type_traits\IsSigned.h" />
<ClInclude Include="..\..\beast\type_traits\RemoveSigned.h" /> <ClInclude Include="..\..\beast\type_traits\RemoveSigned.h" />
<ClInclude Include="..\..\beast\Uncopyable.h" />
<ClInclude Include="..\..\beast\Utility.h" /> <ClInclude Include="..\..\beast\Utility.h" />
<ClInclude Include="..\..\beast\utility\EnableIf.h" /> <ClInclude Include="..\..\beast\utility\EnableIf.h" />
<ClInclude Include="..\..\beast\utility\Journal.h" /> <ClInclude Include="..\..\beast\utility\Journal.h" />
@@ -224,7 +230,6 @@
<ClInclude Include="..\..\modules\beast_core\memory\SharedObject.h" /> <ClInclude Include="..\..\modules\beast_core\memory\SharedObject.h" />
<ClInclude Include="..\..\modules\beast_core\memory\ScopedPointer.h" /> <ClInclude Include="..\..\modules\beast_core\memory\ScopedPointer.h" />
<ClInclude Include="..\..\modules\beast_core\memory\SharedSingleton.h" /> <ClInclude Include="..\..\modules\beast_core\memory\SharedSingleton.h" />
<ClInclude Include="..\..\modules\beast_core\memory\Uncopyable.h" />
<ClInclude Include="..\..\modules\beast_core\memory\WeakReference.h" /> <ClInclude Include="..\..\modules\beast_core\memory\WeakReference.h" />
<ClInclude Include="..\..\modules\beast_core\memory\SharedPtr.h" /> <ClInclude Include="..\..\modules\beast_core\memory\SharedPtr.h" />
<ClInclude Include="..\..\modules\beast_core\memory\StaticObject.h" /> <ClInclude Include="..\..\modules\beast_core\memory\StaticObject.h" />
@@ -286,7 +291,6 @@
<ClInclude Include="..\..\modules\beast_core\threads\ScopedLock.h" /> <ClInclude Include="..\..\modules\beast_core\threads\ScopedLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\ScopedReadLock.h" /> <ClInclude Include="..\..\modules\beast_core\threads\ScopedReadLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\ScopedWriteLock.h" /> <ClInclude Include="..\..\modules\beast_core\threads\ScopedWriteLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\SharedData.h" />
<ClInclude Include="..\..\modules\beast_core\threads\SpinDelay.h" /> <ClInclude Include="..\..\modules\beast_core\threads\SpinDelay.h" />
<ClInclude Include="..\..\modules\beast_core\threads\SpinLock.h" /> <ClInclude Include="..\..\modules\beast_core\threads\SpinLock.h" />
<ClInclude Include="..\..\modules\beast_core\threads\Thread.h" /> <ClInclude Include="..\..\modules\beast_core\threads\Thread.h" />

View File

@@ -204,6 +204,9 @@
<Filter Include="beast\utility\impl"> <Filter Include="beast\utility\impl">
<UniqueIdentifier>{775ab0d6-aa5f-43d7-ab3b-3c01652a9ef1}</UniqueIdentifier> <UniqueIdentifier>{775ab0d6-aa5f-43d7-ab3b-3c01652a9ef1}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="beast\thread">
<UniqueIdentifier>{da8084c0-491b-4eb0-b750-97182a9deed4}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\modules\beast_core\beast_core.h"> <ClInclude Include="..\..\modules\beast_core\beast_core.h">
@@ -576,9 +579,6 @@
<ClInclude Include="..\..\modules\beast_core\diagnostic\Throw.h"> <ClInclude Include="..\..\modules\beast_core\diagnostic\Throw.h">
<Filter>beast_core\diagnostic</Filter> <Filter>beast_core\diagnostic</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\modules\beast_core\memory\Uncopyable.h">
<Filter>beast_core\memory</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\maths\Interval.h"> <ClInclude Include="..\..\modules\beast_core\maths\Interval.h">
<Filter>beast_core\maths</Filter> <Filter>beast_core\maths</Filter>
</ClInclude> </ClInclude>
@@ -699,9 +699,6 @@
<ClInclude Include="..\..\modules\beast_core\threads\ReadWriteMutex.h"> <ClInclude Include="..\..\modules\beast_core\threads\ReadWriteMutex.h">
<Filter>beast_core\threads</Filter> <Filter>beast_core\threads</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\modules\beast_core\threads\SharedData.h">
<Filter>beast_core\threads</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\beast_core\thread\MutexTraits.h"> <ClInclude Include="..\..\modules\beast_core\thread\MutexTraits.h">
<Filter>beast_core\thread</Filter> <Filter>beast_core\thread</Filter>
</ClInclude> </ClInclude>
@@ -1080,6 +1077,24 @@
<ClInclude Include="..\..\beast\mpl\IsCallPossible.h"> <ClInclude Include="..\..\beast\mpl\IsCallPossible.h">
<Filter>beast\mpl</Filter> <Filter>beast\mpl</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\beast\Thread.h">
<Filter>beast</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\thread\LockGuard.h">
<Filter>beast\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\thread\SharedLockGuard.h">
<Filter>beast\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\thread\SharedData.h">
<Filter>beast\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\thread\SharedMutexAdapter.h">
<Filter>beast\thread</Filter>
</ClInclude>
<ClInclude Include="..\..\beast\Uncopyable.h">
<Filter>beast</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\modules\beast_core\containers\AbstractFifo.cpp"> <ClCompile Include="..\..\modules\beast_core\containers\AbstractFifo.cpp">

28
beast/Thread.h Normal file
View File

@@ -0,0 +1,28 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREAD_H_INCLUDED
#define BEAST_THREAD_H_INCLUDED
#include "thread/LockGuard.h"
#include "thread/SharedLockGuard.h"
#include "thread/SharedMutexAdapter.h"
#include "thread/SharedData.h"
#endif

View File

@@ -20,6 +20,11 @@
#ifndef BEAST_UNCOPYABLE_H_INCLUDED #ifndef BEAST_UNCOPYABLE_H_INCLUDED
#define BEAST_UNCOPYABLE_H_INCLUDED #define BEAST_UNCOPYABLE_H_INCLUDED
namespace beast
{
// Ideas from boost
/** Prevent copy construction and assignment. /** Prevent copy construction and assignment.
This is used to suppress warnings and prevent unsafe operations on This is used to suppress warnings and prevent unsafe operations on
@@ -59,12 +64,14 @@
class Uncopyable class Uncopyable
{ {
protected: protected:
inline Uncopyable () { } Uncopyable () { }
inline ~Uncopyable () { } ~Uncopyable () { }
private: private:
Uncopyable (Uncopyable const&); Uncopyable (Uncopyable const&);
Uncopyable const& operator= (Uncopyable const&); Uncopyable const& operator= (Uncopyable const&);
}; };
}
#endif #endif

51
beast/thread/LockGuard.h Normal file
View File

@@ -0,0 +1,51 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREAD_LOCKGUARD_H_INCLUDED
#define BEAST_THREAD_LOCKGUARD_H_INCLUDED
#include "../Uncopyable.h"
namespace beast
{
template <typename Mutex>
class LockGuard : public Uncopyable
{
public:
typedef Mutex MutexType;
explicit LockGuard (Mutex const& mutex)
: m_mutex (mutex)
{
m_mutex.lock();
}
~LockGuard ()
{
m_mutex.unlock();
}
private:
Mutex const& m_mutex;
};
}
#endif

299
beast/thread/SharedData.h Normal file
View File

@@ -0,0 +1,299 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREAD_SHAREDDATA_H_INCLUDED
#define BEAST_THREAD_SHAREDDATA_H_INCLUDED
namespace beast
{
class CriticalSection;
/** Structured, multi-threaded access to a shared state.
This container combines locking semantics with data access semantics to
create an alternative to the typical synchronization method of first
acquiring a lock and then accessing data members.
With this container, access to the underlying data is only possible after
first acquiring a lock. The steps of acquiring the lock and obtaining
a const or non-const reference to the data are combined into one
RAII style operation.
There are three types of access:
- Access
Provides access to the shared state via a non-const reference or pointer.
Access acquires a unique lock on the mutex associated with the
container.
- ConstAccess
Provides access to the shared state via a const reference or pointer.
ConstAccess acquires a shared lock on the mutex associated with the
container.
- UnlockedAccess
Provides access to the shared state via a const reference or pointer.
No locking is performed. It is the callers responsibility to ensure that
the operation is synchronized. This can be useful for diagnostics or
assertions, or for when it is known that no other threads can access
the data.
Usage example:
@code
struct State
{
int value1;
String value2;
};
typedef SharedData <State> SharedState;
SharedState m_state;
void readExample ()
{
SharedState::ConstAccess state (m_state);
print (state->value1); // read access
print (state->value2); // read access
state->value1 = 42; // write disallowed: compile error
}
void writeExample ()
{
SharedState::Access state (m_state);
state->value2 = "Label"; // write access, allowed
}
@endcode
Requirements for Value:
Constructible
Destructible
Requirements for SharedMutexType:
X is SharedMutexType, a is an instance of X:
X a; DefaultConstructible
X::LockGuardType Names a type that implements the LockGuard concept.
X::SharedLockGuardType Names a type that implements the SharedLockGuard concept.
@tparam Value The type which the container holds.
@tparam SharedMutexType The type of shared mutex to use.
*/
template <typename Value, class SharedMutexType =
SharedMutexAdapter <CriticalSection> >
class SharedData : public Uncopyable
{
private:
typedef typename SharedMutexType::LockGuardType LockGuardType;
typedef typename SharedMutexType::SharedLockGuardType SharedLockGuardType;
public:
typedef Value ValueType;
class Access;
class ConstAccess;
class UnlockedAccess;
/** Create a shared data container.
Up to 8 parameters can be specified in the constructor. These parameters
are forwarded to the corresponding constructor in Data. If no
constructor in Data matches the parameter list, a compile error is
generated.
*/
/** @{ */
SharedData () { }
template <class T1>
explicit SharedData (T1 t1)
: m_value (t1) { }
template <class T1, class T2>
SharedData (T1 t1, T2 t2)
: m_value (t1, t2) { }
template <class T1, class T2, class T3>
SharedData (T1 t1, T2 t2, T3 t3)
: m_value (t1, t2, t3) { }
template <class T1, class T2, class T3, class T4>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4)
: m_value (t1, t2, t3, t4) { }
template <class T1, class T2, class T3, class T4, class T5>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
: m_value (t1, t2, t3, t4, t5) { }
template <class T1, class T2, class T3, class T4, class T5, class T6>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
: m_value (t1, t2, t3, t4, t5, t6) { }
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) : m_value (t1, t2, t3, t4, t5, t6, t7) { }
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8)
: m_value (t1, t2, t3, t4, t5, t6, t7, t8) { }
/** @} */
private:
Value m_value;
SharedMutexType m_mutex;
};
//------------------------------------------------------------------------------
/** Provides non-const access to the contents of a SharedData.
This acquires a unique lock on the underlying mutex.
*/
template <class Data, class SharedMutexType>
class SharedData <Data, SharedMutexType>::Access : public Uncopyable
{
public:
explicit Access (SharedData& state)
: m_state (state)
, m_lock (m_state.m_mutex)
{
}
/** Returns a const reference to the data. */
Data const& get () const
{
return m_state.m_value;
}
/** Returns a const reference to the data. */
Data const& operator* () const
{
return get ();
}
/** Returns a const pointer to the data. */
Data const* operator-> () const
{
return &get ();
}
/** Returns a non-const reference to the data. */
Data& get ()
{
return m_state.m_value;
}
/** Returns a non-const reference to the data. */
Data& operator* ()
{
return get ();
}
/** Returns a non-const pointer to the data. */
Data* operator-> ()
{
return &get ();
}
private:
SharedData& m_state;
typename SharedData::LockGuardType m_lock;
};
//------------------------------------------------------------------------------
/** Provides const access to the contents of a SharedData.
This acquires a shared lock on the underlying mutex.
*/
template <class Data, class SharedMutexType>
class SharedData <Data, SharedMutexType>::ConstAccess : public Uncopyable
{
public:
/** Create a ConstAccess from the specified SharedData */
explicit ConstAccess (SharedData const volatile& state)
: m_state (const_cast <SharedData const&> (state))
, m_lock (m_state.m_mutex)
{
}
/** Returns a const reference to the data. */
Data const& get () const
{
return m_state.m_value;
}
/** Returns a const reference to the data. */
Data const& operator* () const
{
return get ();
}
/** Returns a const pointer to the data. */
Data const* operator-> () const
{
return &get ();
}
private:
SharedData const& m_state;
typename SharedData::SharedLockGuardType m_lock;
};
//------------------------------------------------------------------------------
/** Provides const access to the contents of a SharedData.
This acquires a shared lock on the underlying mutex.
*/
template <class Data, class SharedMutexType>
class SharedData <Data, SharedMutexType>::UnlockedAccess : public Uncopyable
{
public:
/** Create an UnlockedAccess from the specified SharedData */
explicit UnlockedAccess (SharedData const volatile& state)
: m_state (const_cast <SharedData const&> (state))
{
}
/** Returns a const reference to the data. */
Data const& get () const
{
return m_state.m_value;
}
/** Returns a const reference to the data. */
Data const& operator* () const
{
return get ();
}
/** Returns a const pointer to the data. */
Data const* operator-> () const
{
return &get ();
}
private:
SharedData const& m_state;
};
}
#endif

View File

@@ -0,0 +1,52 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREAD_SHAREDLOCKGUARD_H_INCLUDED
#define BEAST_THREAD_SHAREDLOCKGUARD_H_INCLUDED
#include "../Uncopyable.h"
namespace beast
{
/** A scoped container that acquires a shared lock. */
template <typename Mutex>
class SharedLockGuard : public Uncopyable
{
public:
typedef Mutex MutexType;
explicit SharedLockGuard (Mutex const& mutex)
: m_mutex (mutex)
{
m_mutex.lock_shared();
}
~SharedLockGuard ()
{
m_mutex.unlock_shared();
}
private:
Mutex const& m_mutex;
};
}
#endif

View File

@@ -0,0 +1,65 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_THREAD_SHAREDMUTEXADAPTER_H_INCLUDED
#define BEAST_THREAD_SHAREDMUTEXADAPTER_H_INCLUDED
namespace beast
{
/** Adapts a regular Lockable to conform to the SharedMutex concept.
Shared locks become unique locks with this interface. Two threads may not
simultaneously acquire ownership of the lock. Typically the Mutex template
parameter will be a CriticalSection.
*/
template <class Mutex>
class SharedMutexAdapter
{
public:
typedef Mutex MutexType;
typedef LockGuard <SharedMutexAdapter> LockGuardType;
typedef SharedLockGuard <SharedMutexAdapter> SharedLockGuardType;
void lock() const
{
m_mutex.lock();
}
void unlock() const
{
m_mutex.unlock();
}
void lock_shared() const
{
m_mutex.lock();
}
void unlock_shared() const
{
m_mutex.unlock();
}
private:
Mutex mutable m_mutex;
};
}
#endif

View File

@@ -78,6 +78,7 @@
#include "../../beast/CStdInt.h" #include "../../beast/CStdInt.h"
#include "../../beast/StaticAssert.h" #include "../../beast/StaticAssert.h"
#include "../../beast/Uncopyable.h"
namespace beast namespace beast
{ {
@@ -94,7 +95,6 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n
// Add new includes to the bottom. // Add new includes to the bottom.
#include "diagnostic/ContractChecks.h" #include "diagnostic/ContractChecks.h"
#include "memory/Uncopyable.h"
#include "memory/Memory.h" #include "memory/Memory.h"
#include "maths/MathsFunctions.h" #include "maths/MathsFunctions.h"
#include "memory/ByteOrder.h" #include "memory/ByteOrder.h"
@@ -108,6 +108,7 @@ extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) n
// New header-only library modeled more closely according to boost // New header-only library modeled more closely according to boost
#include "../../beast/intrusive/ForwardList.h" #include "../../beast/intrusive/ForwardList.h"
#include "../../beast/Net.h" #include "../../beast/Net.h"
#include "../../beast/Thread.h"
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -161,7 +162,6 @@ namespace beast
#include "memory/MemoryAlignment.h" #include "memory/MemoryAlignment.h"
#include "memory/CacheLine.h" #include "memory/CacheLine.h"
#include "threads/ReadWriteMutex.h" #include "threads/ReadWriteMutex.h"
#include "threads/SharedData.h"
#include "diagnostic/SafeBool.h" #include "diagnostic/SafeBool.h"
#include "threads/WaitableEvent.h" #include "threads/WaitableEvent.h"
#include "threads/Thread.h" #include "threads/Thread.h"

View File

@@ -53,7 +53,7 @@ public:
R operator() () R operator() ()
{ {
return m_f (); return (m_f)();
} }
private: private:
@@ -136,7 +136,7 @@ public:
R operator() (P1 p1) R operator() (P1 p1)
{ {
return m_f (p1); return (m_f)(p1);
} }
private: private:

View File

@@ -262,6 +262,22 @@ private:
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// bind() helpers for pointer to member function
template <class T>
const T* get_pointer (SharedPtr<T> const& ptr)
{
return ptr.get();
}
template <class T>
T* get_pointer (SharedPtr<T>& ptr)
{
return ptr.get();
}
//------------------------------------------------------------------------------
/** SharedPtr comparisons. */ /** SharedPtr comparisons. */
/** @{ */ /** @{ */
template <class T, class U> template <class T, class U>

View File

@@ -299,7 +299,7 @@ public:
void stateChanged () void stateChanged ()
{ {
SharedData <SharedState>::ReadAccess state (sharedState); SharedData <SharedState>::ConstAccess state (sharedState);
// (read state) // (read state)
} }
@@ -308,7 +308,7 @@ public:
void changeState () void changeState ()
{ {
SharedData <State>::WriteAccess state (sharedState); SharedData <State>::Access state (sharedState);
// (read and write state) // (read and write state)

View File

@@ -137,7 +137,7 @@
void addListener (Listener* listener, CallQueue& callQueue) void addListener (Listener* listener, CallQueue& callQueue)
{ {
// Acquire read access to the shared state. // Acquire read access to the shared state.
SharedData <State>::ReadAccess state (m_state); SharedData <State>::ConstAccess state (m_state);
// Add the listener. // Add the listener.
m_listeners.add (listener, callQueue); m_listeners.add (listener, callQueue);
@@ -171,7 +171,7 @@
// Update shared state. // Update shared state.
{ {
SharedData <State>::WriteAccess state (m_state); SharedData <State>::Access state (m_state);
m_state->outputLevel = newOutputLevel; m_state->outputLevel = newOutputLevel;
} }

View File

@@ -205,7 +205,7 @@ bool TrackedMutex::Agent::getLockedList (Array <Record>& output)
{ {
TrackedMutex const& mutex = *iter; TrackedMutex const& mutex = *iter;
{ {
TrackedMutex::SharedState::ReadAccess state (mutex.m_state); TrackedMutex::SharedState::ConstAccess state (mutex.m_state);
output.add (state->owner); output.add (state->owner);
} }
} }
@@ -237,7 +237,7 @@ String TrackedMutex::getName () const noexcept
TrackedMutex::Record TrackedMutex::getOwnerRecord () const noexcept TrackedMutex::Record TrackedMutex::getOwnerRecord () const noexcept
{ {
{ {
SharedState::ReadAccess state (m_state); SharedState::ConstAccess state (m_state);
return state->owner; return state->owner;
} }
} }
@@ -245,7 +245,7 @@ TrackedMutex::Record TrackedMutex::getOwnerRecord () const noexcept
TrackedMutex::Agent TrackedMutex::getOwnerAgent () const noexcept TrackedMutex::Agent TrackedMutex::getOwnerAgent () const noexcept
{ {
{ {
SharedState::ReadAccess state (m_state); SharedState::ConstAccess state (m_state);
if (state->thread != nullptr) if (state->thread != nullptr)
return Agent (state->thread); return Agent (state->thread);
} }
@@ -298,7 +298,7 @@ void TrackedMutex::generateGlobalBlockedReport (StringArray& report)
{ {
String s; String s;
TrackedMutex const& mutex (*iter); TrackedMutex const& mutex (*iter);
TrackedMutex::SharedState::ReadAccess state (mutex.m_state); TrackedMutex::SharedState::ConstAccess state (mutex.m_state);
s << " " << mutex.getName () << s << " " << mutex.getName () <<
" from " << state->owner.getSourceLocation (); " from " << state->owner.getSourceLocation ();
report.add (s); report.add (s);
@@ -372,7 +372,7 @@ void TrackedMutex::acquired (char const* fileName, int lineNumber) const noexcep
{ {
// Take a state lock. // Take a state lock.
SharedState::WriteAccess state (m_state); SharedState::Access state (m_state);
// Set the mutex ownership record // Set the mutex ownership record
state->owner = Record (getName (), threadName, sourceLocation); state->owner = Record (getName (), threadName, sourceLocation);
@@ -428,7 +428,7 @@ void TrackedMutex::release () const noexcept
{ {
// Take the mutex' state lock // Take the mutex' state lock
SharedState::WriteAccess state (m_state); SharedState::Access state (m_state);
// Clear the mutex ownership record // Clear the mutex ownership record
state->owner = Record (); state->owner = Record ();

View File

@@ -1,295 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#ifndef BEAST_SHAREDDATA_H_INCLUDED
#define BEAST_SHAREDDATA_H_INCLUDED
/** 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 SharedData:
@code
struct SharedData
{
int value1;
String value2;
};
typedef SharedData <SharedData> 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 <AudioSampleBuffer*> m_array;
};
// Construct SharedData with one parameter
SharedData <SharedData> 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().
*/
template <class Object>
class SharedData : public 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.
*/
/** @{ */
SharedData () { }
template <class T1>
explicit SharedData (T1 t1)
: m_obj (t1) { }
template <class T1, class T2>
SharedData (T1 t1, T2 t2)
: m_obj (t1, t2) { }
template <class T1, class T2, class T3>
SharedData (T1 t1, T2 t2, T3 t3)
: m_obj (t1, t2, t3) { }
template <class T1, class T2, class T3, class T4>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4)
: m_obj (t1, t2, t3, t4) { }
template <class T1, class T2, class T3, class T4, class T5>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
: m_obj (t1, t2, t3, t4, t5) { }
template <class T1, class T2, class T3, class T4, class T5, class T6>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
: m_obj (t1, t2, t3, t4, t5, t6) { }
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7>
SharedData (T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) : m_obj (t1, t2, t3, t4, t5, t6, t7) { }
template <class T1, class T2, class T3, class T4, class T5, class T6, class T7, class T8>
SharedData (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 SharedData.
Use sparingly.
*/
template <class Object>
class SharedData <Object>::UnlockedAccess : public Uncopyable
{
public:
explicit UnlockedAccess (SharedData 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:
SharedData const& m_state;
};
//------------------------------------------------------------------------------
/** Read only access to a SharedData */
template <class Object>
class SharedData <Object>::ReadAccess : public Uncopyable
{
public:
/** Create a ReadAccess from the specified SharedData */
explicit ReadAccess (SharedData const volatile& state)
: m_state (const_cast <SharedData const&> (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:
SharedData const& m_state;
ReadWriteMutexType::ScopedReadLockType m_lock;
};
//------------------------------------------------------------------------------
/** Read/write access to a SharedData */
template <class Object>
class SharedData <Object>::WriteAccess : public Uncopyable
{
public:
explicit WriteAccess (SharedData& 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:
SharedData& m_state;
ReadWriteMutexType::ScopedWriteLockType m_lock;
};
#endif

View File

@@ -21,8 +21,8 @@
*/ */
//============================================================================== //==============================================================================
#ifndef BEAST_THREAD_H_INCLUDED #ifndef BEAST_JUCE_THREAD_H_INCLUDED
#define BEAST_THREAD_H_INCLUDED #define BEAST_JUCE_THREAD_H_INCLUDED
//============================================================================== //==============================================================================
/** /**

View File

@@ -255,7 +255,7 @@ public:
, m_keyBlockDepth (keyBlockDepth) , m_keyBlockDepth (keyBlockDepth)
, m_keyStorage (keyBytes) , m_keyStorage (keyBytes)
{ {
SharedState::WriteAccess state (m_state); SharedState::Access state (m_state);
openFile (&state->keyFile, keyPath); openFile (&state->keyFile, keyPath);
@@ -289,7 +289,7 @@ public:
~KeyvaDBImp () ~KeyvaDBImp ()
{ {
SharedState::WriteAccess state (m_state); SharedState::Access state (m_state);
flushInternal (state); flushInternal (state);
} }
@@ -310,7 +310,7 @@ public:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
Result createMasterRecord (SharedState::WriteAccess& state) Result createMasterRecord (SharedState::Access& state)
{ {
MemoryBlock buffer (masterHeaderBytes, true); MemoryBlock buffer (masterHeaderBytes, true);
@@ -344,7 +344,7 @@ public:
// //
void readKeyRecord (KeyRecord* const keyRecord, void readKeyRecord (KeyRecord* const keyRecord,
KeyIndex const keyIndex, KeyIndex const keyIndex,
SharedState::WriteAccess& state) SharedState::Access& state)
{ {
FileOffset const byteOffset = calcKeyRecordOffset (keyIndex); FileOffset const byteOffset = calcKeyRecordOffset (keyIndex);
@@ -391,7 +391,7 @@ public:
// Write a key record from memory // Write a key record from memory
void writeKeyRecord (KeyRecord const& keyRecord, void writeKeyRecord (KeyRecord const& keyRecord,
KeyIndex const keyIndex, KeyIndex const keyIndex,
SharedState::WriteAccess& state, SharedState::Access& state,
bool includingKey) bool includingKey)
{ {
FileOffset const byteOffset = calcKeyRecordOffset (keyIndex); FileOffset const byteOffset = calcKeyRecordOffset (keyIndex);
@@ -442,7 +442,7 @@ public:
// Append a value to the value file. // Append a value to the value file.
// VFALCO TODO return a Result // VFALCO TODO return a Result
void writeValue (void const* const value, ByteSize valueBytes, SharedState::WriteAccess& state) void writeValue (void const* const value, ByteSize valueBytes, SharedState::Access& state)
{ {
Result result = state->valFile.setPosition (state->valFileSize); Result result = state->valFile.setPosition (state->valFileSize);
@@ -493,7 +493,7 @@ public:
// //
// Returns true if the key was found. // Returns true if the key was found.
// //
bool find (FindResult* findResult, void const* key, SharedState::WriteAccess& state) bool find (FindResult* findResult, void const* key, SharedState::Access& state)
{ {
// Not okay to call this with an empty key file! // Not okay to call this with an empty key file!
bassert (state->hasKeys ()); bassert (state->hasKeys ());
@@ -546,7 +546,7 @@ public:
{ {
FindResult findResult (m_keyStorage.getData ()); FindResult findResult (m_keyStorage.getData ());
SharedState::WriteAccess state (m_state); SharedState::Access state (m_state);
bool found = false; bool found = false;
@@ -594,7 +594,7 @@ public:
{ {
bassert (valueBytes > 0); bassert (valueBytes > 0);
SharedState::WriteAccess state (m_state); SharedState::Access state (m_state);
if (state->hasKeys ()) if (state->hasKeys ())
{ {
@@ -681,12 +681,12 @@ public:
void flush () void flush ()
{ {
SharedState::WriteAccess state (m_state); SharedState::Access state (m_state);
flushInternal (state); flushInternal (state);
} }
void flushInternal (SharedState::WriteAccess& state) void flushInternal (SharedState::Access& state)
{ {
state->keyFile.flush (); state->keyFile.flush ();
state->valFile.flush (); state->valFile.flush ();