Files
tenmon/3rdparty/include/pcl/AutoLock.h
T
2022-04-12 08:17:18 +02:00

381 lines
12 KiB
C++

// ____ ______ __
// / __ \ / ____// /
// / /_/ // / / /
// / ____// /___ / /___ PixInsight Class Library
// /_/ \____//_____/ PCL 2.4.23
// ----------------------------------------------------------------------------
// pcl/AutoLock.h - Released 2022-03-12T18:59:29Z
// ----------------------------------------------------------------------------
// This file is part of the PixInsight Class Library (PCL).
// PCL is a multiplatform C++ framework for development of PixInsight modules.
//
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
//
// Redistribution and use in both source and binary forms, with or without
// modification, is permitted provided that the following conditions are met:
//
// 1. All redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. All redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
// of their contributors, may be used to endorse or promote products derived
// from this software without specific prior written permission. For written
// permission, please contact info@pixinsight.com.
//
// 4. All products derived from this software, in any form whatsoever, must
// reproduce the following acknowledgment in the end-user documentation
// and/or other materials provided with the product:
//
// "This product is based on software from the PixInsight project, developed
// by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
//
// Alternatively, if that is where third-party acknowledgments normally
// appear, this acknowledgment must be reproduced in the product itself.
//
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------
#ifndef __PCL_AutoLock_h
#define __PCL_AutoLock_h
/// \file pcl/AutoLock.h
#include <pcl/Defs.h>
#include <pcl/Diagnostics.h>
#include <pcl/Atomic.h>
#include <pcl/Mutex.h>
namespace pcl
{
// ----------------------------------------------------------------------------
/*!
* \class AutoLock
* \brief Automatic mutex lock/unlock.
*
* %AutoLock is a convenience class that simplifies using Mutex objects to
* protect code or data that can be accessed by multiple threads.
*
* An %AutoLock object locks a %Mutex object upon construction and unlocks it
* upon destruction. This ensures that the state of the %Mutex object will
* always be well defined, and that it will never be left locked, even in
* critical situations involving multiple function return points and
* exceptions.
*
* \sa AutoLockCounter, Mutex
*/
class PCL_CLASS AutoLock
{
public:
/*!
* Constructs an %AutoLock object to monitor a specified Mutex object.
*
* \param mutex A %Mutex object that will be monitored by this %AutoLock
* instance.
*
* The specified mutex object will be locked by this constructor. It will be
* unlocked automatically when this %AutoLock object gets out of scope, or
* if it is destroyed explicitly.
*/
explicit AutoLock( pcl::Mutex& mutex )
: m_mutex( &mutex )
{
Lock();
}
/*!
* Move constructor.
*/
AutoLock( AutoLock&& x )
: m_mutex( x.m_mutex )
, m_lock( x.m_lock )
{
x.m_mutex = nullptr;
}
/*!
* Destroys this %AutoLock object.
*
* If the monitored mutex object (that was specified in the constructor) is
* locked, it is unlocked by this destructor.
*/
~AutoLock()
{
Unlock();
m_mutex = nullptr;
}
/*!
* Copy constructor. This constructor is disabled because %AutoLock objects
* cannot be copied.
*/
AutoLock( const AutoLock& ) = delete;
/*!
* Copy assignment. This operator is disabled because %AutoLock objects
* cannot be copied.
*/
AutoLock& operator =( const AutoLock& ) = delete;
/*!
* Move assignment. This operator is disabled because %AutoLock objects
* cannot be move-assigned.
*/
AutoLock& operator =( AutoLock&& ) = delete;
/*!
* Locks the monitored mutex object, if it has not been previously locked by
* this object.
*/
void Lock()
{
if ( m_mutex != nullptr )
if ( m_lock.TestAndSet( 0, 1 ) )
m_mutex->Lock();
}
/*!
* Unlocks the monitored mutex object, if it has been previously locked by
* this object.
*/
void Unlock()
{
if ( m_mutex != nullptr )
if ( m_lock.TestAndSet( 1, 0 ) )
m_mutex->Unlock();
}
private:
pcl::Mutex* m_mutex = nullptr;
AtomicInt m_lock;
};
// ----------------------------------------------------------------------------
/*!
* \class AutoLockCounter
* \brief Automatic mutex lock/unlock with limited concurrent access allowance.
*
* %AutoLockCounter is similar to AutoLock: it allows protecting a section of
* code against concurrent thread access through a Mutex, with automatic
* lock/unlock operations upon object construction/destruction. However,
* %AutoLockCounter is slightly more complex because it can allow a specified
* amount of concurrent accesses, while %AutoLock forbids them completely.
*
* %AutoLockCounter is useful for scenarios where the protected code can
* exploit a resource concurrently, but only to a given extent that can be
* predicted or configured. Typical examples are routines performing file
* read/write operations.
*
* Example:
*
* \code
* void ParallelWriteFile( const String& filePath, const ByteArray& data, int limit )
* {
* static Mutex mutex;
* static AtomicInt count;
* volatile AutoLockCounter lock( mutex, count, limit );
* File::WriteFile( filePath, data );
* }
* \endcode
*
* In this example, the ParallelWriteFile routine allows creating and writing
* up to \e limit different disk files simultaneously. If \e limit files are
* already being written concurrently, a new call to ParallelWriteFile() will
* block the caller thread until at least one of the running tasks terminates.
*
* \sa AutoLock, Mutex, AtomicInt
*/
class PCL_CLASS AutoLockCounter
{
public:
/*!
* Constructs an %AutoLockCounter object to monitor a Mutex with automatic
* counting of lock operations and a given maximum number of concurrent
* accesses.
*
* \param mutex Reference to a Mutex object that will be monitored by this
* %AutoLockCounter instance.
*
* \param count Reference to an AtomicInt object that will be updated by
* this instance to control the current amount of concurrent
* accesses.
*
* \param limit Maximum number of concurrent accesses allowed. The
* specified \a count variable will be atomically incremented
* by this constructor. If \a count is greater than \a limit
* after the increment, this constructor will lock the
* specified \a mutex. Otherwise the mutex will not be locked
* automatically upon construction. Note that the mutex can
* be locked explicitly by calling the Lock() member function
* for any AutoLock or AutoLockCounter object sharing the
* same \a mutex variable.
*
* By specifying a \a limit of zero, no concurrent access will be allowed
* and this object will be functionally equivalent to an AutoLock instance
* monitoring the same \a mutex. By setting \a limit to a value greater than
* or equal to one, the protected code section will be allowed to run once,
* twice, etc. without a (potentially expensive) lock operation.
*
* If the specified \a mutex has been locked by this object, be it
* automatically or explicitly, it will be unlocked automatically when this
* %AutoLockCounter object is destroyed or gets out of scope.
*/
explicit AutoLockCounter( pcl::Mutex& mutex, AtomicInt& count, int limit )
: m_mutex( &mutex )
, m_count( &count )
, m_lock( 0 )
{
if ( m_count->FetchAndAdd( 1 ) >= limit-1 )
{
Lock();
if ( m_count->Load() < limit )
Unlock();
}
}
/*!
* Move constructor.
*/
AutoLockCounter( AutoLockCounter&& x )
: m_mutex( x.m_mutex )
, m_count( x.m_count )
, m_lock( x.m_lock )
{
x.m_mutex = nullptr;
x.m_count = nullptr;
}
/*!
* Destroys this %AutoLockCounter object.
*
* This destructor performs two separate actions:
*
* - If the monitored mutex (which was specified in the constructor) has
* been locked by this object, it will be unlocked. This applies both if the
* mutex has been locked automatically upon construction (because the
* monitored counter was larger than the specified limit), or explicitly by
* calling the Lock() member function for this object.
*
* - The monitored counter, which was atomically incremented upon
* construction, will be atomically decremented.
*/
~AutoLockCounter()
{
Unlock();
m_mutex = nullptr;
if ( m_count != nullptr )
{
m_count->Decrement();
m_count = nullptr;
}
}
/*!
* Copy constructor. This constructor is disabled because %AutoLockCounter
* objects cannot be copied.
*/
AutoLockCounter( const AutoLockCounter& ) = delete;
/*!
* Copy assignment. This operator is disabled because %AutoLockCounter
* objects cannot be copied.
*/
AutoLockCounter& operator =( const AutoLockCounter& ) = delete;
/*!
* Move assignment. This operator is disabled because %AutoLockCounter
* objects cannot be move-assigned.
*/
AutoLockCounter& operator =( AutoLockCounter&& ) = delete;
/*!
* Locks the monitored mutex object, if it has not been previously locked by
* this object.
*/
void Lock()
{
if ( m_mutex != nullptr )
if ( m_lock.TestAndSet( 0, 1 ) )
m_mutex->Lock();
}
/*!
* Unlocks the monitored mutex object, if it has been previously locked by
* this object.
*/
void Unlock()
{
if ( m_mutex != nullptr )
if ( m_lock.TestAndSet( 1, 0 ) )
m_mutex->Unlock();
}
private:
pcl::Mutex* m_mutex = nullptr;
AtomicInt* m_count = nullptr;
AtomicInt m_lock;
};
// ----------------------------------------------------------------------------
/*!
* \def Synchronized
* \brief A macro to protect a simple fragment of code with a Mutex object.
*
* Example of use:
*
* \code
* Mutex mutex;
* ...
* Synchronized( mutex, count += img.Width(); )
* \endcode
*
* The protected code should not contain tokens that could invalidate macro
* argument semantics. To synchronize more complex pieces of code, use an
* AutoLock object explicitly. For example:
*
* \code
* Mutex mutex;
* ...
* {
* AutoLock locker( mutex );
* ... some code to protect here ...
* }
* \endcode
*/
#define Synchronized( mutex, code ) \
{ \
pcl::AutoLock _________( mutex ); \
code \
}
// ----------------------------------------------------------------------------
} // pcl
#endif // __PCL_AutoLock_h
// ----------------------------------------------------------------------------
// EOF pcl/AutoLock.h - Released 2022-03-12T18:59:29Z