245 lines
8.3 KiB
C++
245 lines
8.3 KiB
C++
/*
|
|
==============================================================================
|
|
|
|
This file is part of the JUCE library.
|
|
Copyright (c) 2017 - ROLI Ltd.
|
|
|
|
JUCE is an open source library subject to commercial or open-source
|
|
licensing.
|
|
|
|
The code included in this file is provided under the terms of the ISC license
|
|
http://www.isc.org/downloads/software-support-policy/isc-license. 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.
|
|
|
|
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
|
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
|
DISCLAIMED.
|
|
|
|
==============================================================================
|
|
*/
|
|
|
|
namespace juce
|
|
{
|
|
|
|
//==============================================================================
|
|
/**
|
|
Automatically locks and unlocks a mutex object.
|
|
|
|
Use one of these as a local variable to provide RAII-based locking of a mutex.
|
|
|
|
The templated class could be a CriticalSection, SpinLock, or anything else that
|
|
provides enter() and exit() methods.
|
|
|
|
e.g. @code
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
|
|
// myCriticalSection is now locked
|
|
|
|
...do some stuff...
|
|
|
|
// myCriticalSection gets unlocked here.
|
|
}
|
|
@endcode
|
|
|
|
@see GenericScopedUnlock, CriticalSection, SpinLock, ScopedLock, ScopedUnlock
|
|
|
|
@tags{Core}
|
|
*/
|
|
template <class LockType>
|
|
class GenericScopedLock
|
|
{
|
|
public:
|
|
//==============================================================================
|
|
/** Creates a GenericScopedLock.
|
|
|
|
As soon as it is created, this will acquire the lock, and when the GenericScopedLock
|
|
object is deleted, the lock will be released.
|
|
|
|
Make sure this object is created and deleted by the same thread,
|
|
otherwise there are no guarantees what will happen! Best just to use it
|
|
as a local stack object, rather than creating one with the new() operator.
|
|
*/
|
|
inline explicit GenericScopedLock (const LockType& lock) noexcept : lock_ (lock) { lock.enter(); }
|
|
|
|
/** Destructor.
|
|
The lock will be released when the destructor is called.
|
|
Make sure this object is created and deleted by the same thread, otherwise there are
|
|
no guarantees what will happen!
|
|
*/
|
|
inline ~GenericScopedLock() noexcept { lock_.exit(); }
|
|
|
|
private:
|
|
//==============================================================================
|
|
const LockType& lock_;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (GenericScopedLock)
|
|
};
|
|
|
|
|
|
//==============================================================================
|
|
/**
|
|
Automatically unlocks and re-locks a mutex object.
|
|
|
|
This is the reverse of a GenericScopedLock object - instead of locking the mutex
|
|
for the lifetime of this object, it unlocks it.
|
|
|
|
Make sure you don't try to unlock mutexes that aren't actually locked!
|
|
|
|
e.g. @code
|
|
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
|
|
// myCriticalSection is now locked
|
|
|
|
... do some stuff with it locked ..
|
|
|
|
while (xyz)
|
|
{
|
|
... do some stuff with it locked ..
|
|
|
|
const GenericScopedUnlock<CriticalSection> unlocker (myCriticalSection);
|
|
|
|
// myCriticalSection is now unlocked for the remainder of this block,
|
|
// and re-locked at the end.
|
|
|
|
...do some stuff with it unlocked ...
|
|
}
|
|
|
|
// myCriticalSection gets unlocked here.
|
|
}
|
|
@endcode
|
|
|
|
@see GenericScopedLock, CriticalSection, ScopedLock, ScopedUnlock
|
|
|
|
@tags{Core}
|
|
*/
|
|
template <class LockType>
|
|
class GenericScopedUnlock
|
|
{
|
|
public:
|
|
//==============================================================================
|
|
/** Creates a GenericScopedUnlock.
|
|
|
|
As soon as it is created, this will unlock the CriticalSection, and
|
|
when the ScopedLock object is deleted, the CriticalSection will
|
|
be re-locked.
|
|
|
|
Make sure this object is created and deleted by the same thread,
|
|
otherwise there are no guarantees what will happen! Best just to use it
|
|
as a local stack object, rather than creating one with the new() operator.
|
|
*/
|
|
inline explicit GenericScopedUnlock (const LockType& lock) noexcept : lock_ (lock) { lock.exit(); }
|
|
|
|
/** Destructor.
|
|
|
|
The CriticalSection will be unlocked when the destructor is called.
|
|
|
|
Make sure this object is created and deleted by the same thread,
|
|
otherwise there are no guarantees what will happen!
|
|
*/
|
|
inline ~GenericScopedUnlock() noexcept { lock_.enter(); }
|
|
|
|
|
|
private:
|
|
//==============================================================================
|
|
const LockType& lock_;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (GenericScopedUnlock)
|
|
};
|
|
|
|
|
|
//==============================================================================
|
|
/**
|
|
Automatically locks and unlocks a mutex object.
|
|
|
|
Use one of these as a local variable to provide RAII-based locking of a mutex.
|
|
|
|
The templated class could be a CriticalSection, SpinLock, or anything else that
|
|
provides enter() and exit() methods.
|
|
|
|
e.g. @code
|
|
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const GenericScopedTryLock<CriticalSection> myScopedTryLock (myCriticalSection);
|
|
|
|
// Unlike using a ScopedLock, this may fail to actually get the lock, so you
|
|
// should test this with the isLocked() method before doing your thread-unsafe
|
|
// action..
|
|
if (myScopedTryLock.isLocked())
|
|
{
|
|
...do some stuff...
|
|
}
|
|
else
|
|
{
|
|
..our attempt at locking failed because another thread had already locked it..
|
|
}
|
|
|
|
// myCriticalSection gets unlocked here (if it was locked)
|
|
}
|
|
@endcode
|
|
|
|
@see CriticalSection::tryEnter, GenericScopedLock, GenericScopedUnlock
|
|
|
|
@tags{Core}
|
|
*/
|
|
template <class LockType>
|
|
class GenericScopedTryLock
|
|
{
|
|
public:
|
|
//==============================================================================
|
|
/** Creates a GenericScopedTryLock.
|
|
|
|
If acquireLockOnInitialisation is true then as soon as this ScopedTryLock
|
|
is created, it will attempt to acquire the lock with tryEnter.
|
|
|
|
You can retry acquiring the lock by calling retryLock.
|
|
|
|
When GenericScopedTryLock is deleted, the lock will be released (if the lock
|
|
was successfully acquired).
|
|
|
|
Make sure this object is created and deleted by the same thread,
|
|
otherwise there are no guarantees what will happen! Best just to use it
|
|
as a local stack object, rather than creating one with the new() operator.
|
|
|
|
@see retryLock, isLocked
|
|
*/
|
|
inline explicit GenericScopedTryLock (const LockType& lock, bool acquireLockOnInitialisation = true) noexcept
|
|
: lock_ (lock), lockWasSuccessful (acquireLockOnInitialisation && lock.tryEnter()) {}
|
|
|
|
/** Destructor.
|
|
|
|
The mutex will be unlocked (if it had been successfully locked) when the
|
|
destructor is called.
|
|
|
|
Make sure this object is created and deleted by the same thread,
|
|
otherwise there are no guarantees what will happen!
|
|
*/
|
|
inline ~GenericScopedTryLock() noexcept { if (lockWasSuccessful) lock_.exit(); }
|
|
|
|
/** Returns true if the mutex was successfully locked. */
|
|
bool isLocked() const noexcept { return lockWasSuccessful; }
|
|
|
|
/** Retry gaining the lock by calling tryEnter on the underlying lock. */
|
|
bool retryLock() const noexcept { lockWasSuccessful = lock_.tryEnter(); return lockWasSuccessful; }
|
|
|
|
private:
|
|
//==============================================================================
|
|
const LockType& lock_;
|
|
mutable bool lockWasSuccessful;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (GenericScopedTryLock)
|
|
};
|
|
|
|
} // namespace juce
|