671 lines
21 KiB
C++
671 lines
21 KiB
C++
// ____ ______ __
|
|
// / __ \ / ____// /
|
|
// / /_/ // / / /
|
|
// / ____// /___ / /___ PixInsight Class Library
|
|
// /_/ \____//_____/ PCL 2.4.23
|
|
// ----------------------------------------------------------------------------
|
|
// pcl/Atomic.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_Atomic_h
|
|
#define __PCL_Atomic_h
|
|
|
|
/// \file pcl/Atomic.h
|
|
|
|
#include <pcl/Defs.h>
|
|
|
|
#ifdef __PCL_WINDOWS
|
|
# include <intrin.h>
|
|
#ifdef _MSC_VER
|
|
# pragma intrinsic (_InterlockedIncrement)
|
|
# pragma intrinsic (_InterlockedDecrement)
|
|
# pragma intrinsic (_InterlockedCompareExchange)
|
|
# pragma intrinsic (_InterlockedExchange)
|
|
# pragma intrinsic (_InterlockedExchangeAdd)
|
|
#endif
|
|
#endif
|
|
|
|
namespace pcl
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class AtomicInt
|
|
* \brief Atomic operations on integers.
|
|
*
|
|
* %AtomicInt allows non-blocking synchronization of multithreaded code with
|
|
* respect to reference counting and other critical operations in parallel
|
|
* algorithm implementations. This class is used extensively by PCL code to
|
|
* implement copy-on-write shared containers and container operations in a
|
|
* thread-safe way. An example is the ReferenceCounter class, which is at the
|
|
* hearth of most PCL container and image classes.
|
|
*
|
|
* %AtomicInt implements the following synchronization primitives on integers:
|
|
*
|
|
* reference \n
|
|
* dereference \n
|
|
* test-and-set \n
|
|
* fetch-and-store \n
|
|
* fetch-and-add
|
|
*
|
|
* \sa ReferenceCounter
|
|
*/
|
|
class PCL_CLASS AtomicInt
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs an %AtomicInt instance with the specified \a value. When not
|
|
* explicitly specified, the default value is zero.
|
|
*/
|
|
AtomicInt( int value = 0 )
|
|
: m_value( value )
|
|
{
|
|
// ### N.B.:
|
|
// The default zero initialization is *critical* - DO NOT change it.
|
|
}
|
|
|
|
/*!
|
|
* Copy constructor.
|
|
*/
|
|
AtomicInt( const AtomicInt& ) = default;
|
|
|
|
/*!
|
|
* Copy assignment operator. Returns a reference to this object.
|
|
*/
|
|
AtomicInt& operator =( const AtomicInt& ) = default;
|
|
|
|
/*!
|
|
* Returns the current value of this atomic integer.
|
|
*
|
|
* \note This operation is not guaranteed to be atomic.
|
|
*/
|
|
operator int() const
|
|
{
|
|
return m_value;
|
|
}
|
|
|
|
/*!
|
|
* Logical negation operator. Returns true iff this atomic integer is zero.
|
|
*
|
|
* \note This operation is not guaranteed to be atomic.
|
|
*/
|
|
bool operator !() const
|
|
{
|
|
return m_value == 0;
|
|
}
|
|
|
|
/*!
|
|
* Equality operator. Returns true iff this atomic integer is equal to an
|
|
* integer \a x.
|
|
*
|
|
* \note This operation is not guaranteed to be atomic.
|
|
*/
|
|
bool operator ==( int x ) const
|
|
{
|
|
return m_value == x;
|
|
}
|
|
|
|
/*!
|
|
* Inequality operator. Returns true iff this atomic integer is not equal to
|
|
* an integer \a x.
|
|
*
|
|
* \note This operation is not guaranteed to be atomic.
|
|
*/
|
|
bool operator !=( int x ) const
|
|
{
|
|
return m_value != x;
|
|
}
|
|
|
|
/*!
|
|
* Integer assignment operator. Assigns the specified integer \a x to this
|
|
* atomic integer. Returns a reference to this object.
|
|
*
|
|
* \note This operation is not guaranteed to be atomic.
|
|
*/
|
|
AtomicInt& operator =( int x )
|
|
{
|
|
m_value = x;
|
|
return *this;
|
|
}
|
|
|
|
/*!
|
|
* Atomic load operation.
|
|
*
|
|
* Returns the current value of this atomic integer.
|
|
*
|
|
* \note The integer load operation is guaranteed to be atomic on all
|
|
* supported platforms and architectures.
|
|
*/
|
|
int Load()
|
|
{
|
|
return FetchAndAdd( 0 );
|
|
}
|
|
|
|
/*!
|
|
* Atomic store operation.
|
|
*
|
|
* Assigns the specified \a newValue to this object.
|
|
*
|
|
* \note The integer store operation is guaranteed to be atomic on all
|
|
* supported platforms and architectures.
|
|
*/
|
|
void Store( int newValue )
|
|
{
|
|
(void)FetchAndStore( newValue );
|
|
}
|
|
|
|
/*!
|
|
* Atomic increment operation.
|
|
*
|
|
* Increments the value of this object as an atomic operation.
|
|
*
|
|
* \note This operation is guaranteed to be atomic on all supported
|
|
* platforms and architectures.
|
|
*/
|
|
void Increment()
|
|
{
|
|
#ifdef __PCL_WINDOWS
|
|
(void)_InterlockedIncrement( &m_value );
|
|
#else
|
|
asm volatile( "lock\n\t"
|
|
"incl %0\n"
|
|
: "=m" (m_value)
|
|
: "m" (m_value)
|
|
: "memory", "cc" );
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Atomic decrement operation.
|
|
*
|
|
* Decrements the value of this object as an atomic operation.
|
|
*
|
|
* \note This operation is guaranteed to be atomic on all supported
|
|
* platforms and architectures.
|
|
*/
|
|
void Decrement()
|
|
{
|
|
#ifdef __PCL_WINDOWS
|
|
(void)_InterlockedDecrement( &m_value );
|
|
#else
|
|
asm volatile( "lock\n\t"
|
|
"decl %0\n"
|
|
: "=m" (m_value)
|
|
: "m" (m_value)
|
|
: "memory", "cc" );
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Atomic reference operation.
|
|
*
|
|
* Increments the value of this object as an atomic operation. Returns true
|
|
* if the resulting value after incrementing this object is nonzero.
|
|
*
|
|
* \note This operation is guaranteed to be atomic on all supported
|
|
* platforms and architectures.
|
|
*/
|
|
bool Reference()
|
|
{
|
|
#ifdef __PCL_WINDOWS
|
|
return _InterlockedIncrement( &m_value ) != 0;
|
|
#else
|
|
uint8 result;
|
|
asm volatile( "lock\n\t"
|
|
"incl %0\n\t"
|
|
"setnz %1\n"
|
|
: "=m" (m_value), "=qm" (result)
|
|
: "m" (m_value)
|
|
: "memory", "cc" );
|
|
return result != 0;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Atomic dereference operation.
|
|
*
|
|
* Decrements the value of this object as an atomic operation. Returns true
|
|
* if the resulting value after decrementing this object is nonzero.
|
|
*
|
|
* \note This operation is guaranteed to be atomic on all supported
|
|
* platforms and architectures.
|
|
*/
|
|
bool Dereference()
|
|
{
|
|
#ifdef __PCL_WINDOWS
|
|
return _InterlockedDecrement( &m_value ) != 0;
|
|
#else
|
|
uint8 result;
|
|
asm volatile( "lock\n\t"
|
|
"decl %0\n\t"
|
|
"setnz %1\n"
|
|
: "=m" (m_value), "=qm" (result)
|
|
: "m" (m_value)
|
|
: "memory", "cc" );
|
|
return result != 0;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Atomic test-and-set operation.
|
|
*
|
|
* If the current value of this object is equal to \a expectedValue, this
|
|
* function assigns \a newValue to this object and returns true. If the
|
|
* current value is not equal to \a expectedValue, this function performs no
|
|
* operation and returns false.
|
|
*
|
|
* \note This operation is guaranteed to be atomic on all supported
|
|
* platforms and architectures.
|
|
*/
|
|
bool TestAndSet( int expectedValue, int newValue )
|
|
{
|
|
#ifdef __PCL_WINDOWS
|
|
return _InterlockedCompareExchange( &m_value, newValue, expectedValue ) == expectedValue;
|
|
#else
|
|
uint8 result;
|
|
asm volatile( "lock\n\t"
|
|
"cmpxchgl %3,%2\n\t"
|
|
"setz %1\n"
|
|
: "=a" (newValue), "=qm" (result), "+m" (m_value)
|
|
: "r" (newValue), "0" (expectedValue)
|
|
: "memory", "cc" );
|
|
return result != 0;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Atomic fetch-and-store operation.
|
|
*
|
|
* Assigns \a newValue to this object and returns the initial value before
|
|
* assignment, as an atomic operation.
|
|
*
|
|
* \note This operation is guaranteed to be atomic on all supported
|
|
* platforms and architectures.
|
|
*/
|
|
int FetchAndStore( int newValue )
|
|
{
|
|
#ifdef __PCL_WINDOWS
|
|
return _InterlockedExchange( &m_value, newValue );
|
|
#else
|
|
asm volatile( "xchgl %0,%1\n"
|
|
: "=r" (newValue), "+m" (m_value)
|
|
: "0" (newValue)
|
|
: "memory" );
|
|
return newValue;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
* Atomic fetch-and-add operation. Adds \a valueToAdd to this object and
|
|
* returns the initial value before addition, as an atomic operation.
|
|
*
|
|
* \note This operation is guaranteed to be atomic on all supported
|
|
* platforms and architectures.
|
|
*/
|
|
int FetchAndAdd( int valueToAdd )
|
|
{
|
|
#ifdef __PCL_WINDOWS
|
|
return _InterlockedExchangeAdd( &m_value, valueToAdd );
|
|
#else
|
|
asm volatile( "lock\n\t"
|
|
"xaddl %0,%1\n"
|
|
: "=r" (valueToAdd), "+m" (m_value)
|
|
: "0" (valueToAdd)
|
|
: "memory", "cc" );
|
|
return valueToAdd;
|
|
#endif
|
|
}
|
|
|
|
private:
|
|
|
|
#ifdef _MSC_VER
|
|
__declspec(align(4)) volatile long m_value;
|
|
#elif __PCL_WINDOWS
|
|
volatile long m_value __attribute__ ((aligned (4)));
|
|
#else
|
|
volatile int m_value __attribute__ ((aligned (4)));
|
|
#endif
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \defgroup reentrancy_protection Thread-Safe Protection of Non-Reentrant Code
|
|
*/
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class AutoReentrancyGuard
|
|
* \brief Automatic reentrancy guard sentinel.
|
|
*
|
|
* %AutoReentrancyGuard allows you to protect a block of code ensuring that it
|
|
* cannot be reentrant. All you need is a static AtomicInt variable that works
|
|
* as a 'busy state' flag persistent across function invocations.
|
|
*
|
|
* Consider the following example:
|
|
*
|
|
* \code void foo()
|
|
* {
|
|
* static AtomicInt flag;
|
|
* AutoReentrancyGuard guard( flag );
|
|
* if ( guard )
|
|
* {
|
|
* // protected code
|
|
* }
|
|
* }
|
|
* \endcode
|
|
*
|
|
* The function \c foo is not reentrant, so we want to protect it against
|
|
* possible reentrant invocations while the function's code is being executed.
|
|
*
|
|
* The \c flag variable is initially zero (because AtomicInt's default
|
|
* constructor initializes its integer member to zero). The first time \c foo
|
|
* is called, %AutoReentrancyGuard's constructor can change the value of
|
|
* \c flag from zero to one as an atomic operation. When this happens,
|
|
* AutoReentrancyGuard::operator bool() returns true, and the code protected
|
|
* within the \c if block can be executed.
|
|
*
|
|
* When the \c guard object gets out of scope (just before the \c foo function
|
|
* returns), its class destructor resets \c flag to zero automatically, which
|
|
* permits the next non-reentrant execution of \c foo. However, if \c foo is
|
|
* called again before \c guard is destroyed, a newly constructed
|
|
* %AutoReentrancyGuard object cannot make a transition 0 -> 1 with the static
|
|
* \c flag variable, and hence a reentrant execution of the protected code is
|
|
* not allowed (in this case, the function simply does nothing and returns
|
|
* after the \c if block). Note that the protected code can freely return from
|
|
* the function or throw exceptions; the \c flag variable will be reset to zero
|
|
* automatically when \c guard gets out of scope.
|
|
*
|
|
* Since %AutoReentrancyGuard uses AtomicInt to implement atomic transitions,
|
|
* code blocks can be protected against reentrant execution in multithreaded
|
|
* environments.
|
|
*
|
|
* The macros PCL_REENTRANCY_GUARDED_BEGIN and PCL_REENTRANCY_GUARDED_END
|
|
* greatly simplify reentrancy protection. For example, the above code could be
|
|
* implemented as follows:
|
|
*
|
|
* \code void foo()
|
|
* {
|
|
* PCL_REENTRANCY_GUARDED_BEGIN
|
|
* // protected code
|
|
* PCL_REENTRANCY_GUARDED_END
|
|
* } \endcode
|
|
*
|
|
* In addition, the macros PCL_CLASS_REENTRANCY_GUARD and
|
|
* PCL_CLASS_REENTRANCY_GUARDED_BEGIN are useful for protection of all
|
|
* non-reentrant member functions of a class, and the macros
|
|
* PCL_MEMBER_REENTRANCY_GUARD and PCL_MEMBER_REENTRANCY_GUARDED_BEGIN provide
|
|
* protection of specific member functions. See these macros for examples.
|
|
*
|
|
* \ingroup reentrancy_protection
|
|
*/
|
|
class AutoReentrancyGuard
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* Constructs an %AutoReentrancyGuard object to monitor the specified
|
|
* \a guard variable. If \c guard is zero, its value is set to one as an
|
|
* atomic operation. If \c guard is nonzero, its value is not changed.
|
|
*
|
|
* \warning The monitored guard variable *must* be either a static variable
|
|
* local to the function being protected, or a data member of the same class
|
|
* to which a protected member function belongs. Otherwise the protection
|
|
* mechanism will not work. This can be dangerous, especially because you
|
|
* may erroneously think that your code is being protected when it is not.
|
|
* In addition, the guard variable must be zero initially, or the protected
|
|
* code will never be allowed to work. We strongly recommend you don't use
|
|
* this class directly, but the PCL_REENTRANCY_GUARDED_BEGIN and
|
|
* PCL_REENTRANCY_GUARDED_END macros to implement function level protection,
|
|
* or PCL_CLASS_REENTRANCY_GUARD, PCL_CLASS_REENTRANCY_GUARDED_BEGIN and
|
|
* PCL_CLASS_REENTRANCY_GUARDED_END to implement per-instance function
|
|
* member protection.
|
|
*/
|
|
AutoReentrancyGuard( AtomicInt& guard )
|
|
: m_guard( guard )
|
|
{
|
|
m_guarded = m_guard.TestAndSet( 0, 1 );
|
|
}
|
|
|
|
/*!
|
|
* Destroys this object. If the value of the monitored guard variable (see
|
|
* the class constructor) was zero when this object was constructed, its
|
|
* value is reset to zero as an atomic operation.
|
|
*/
|
|
~AutoReentrancyGuard()
|
|
{
|
|
if ( m_guarded )
|
|
m_guard.Store( 0 );
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff the value of the monitored guard variable (see the class
|
|
* constructor) was zero when this object was constructed.
|
|
*/
|
|
operator bool() const volatile
|
|
{
|
|
return m_guarded;
|
|
}
|
|
|
|
private:
|
|
|
|
AtomicInt& m_guard;
|
|
bool m_guarded = false;
|
|
};
|
|
|
|
/*!
|
|
* \def PCL_REENTRANCY_GUARDED_BEGIN
|
|
*
|
|
* This macro along with PCL_REENTRANCY_GUARDED_END simplifies protection of
|
|
* non-reentrant code. See the AutoReentrancyGuard class for detailed
|
|
* information and examples.
|
|
*
|
|
* \ingroup reentrancy_protection
|
|
*/
|
|
#define PCL_REENTRANCY_GUARDED_BEGIN \
|
|
{ \
|
|
static pcl::AtomicInt __r_g__( 0 ); \
|
|
volatile pcl::AutoReentrancyGuard __a_r_g__( __r_g__ ); \
|
|
if ( __a_r_g__ ) \
|
|
{
|
|
|
|
/*!
|
|
* \def PCL_REENTRANCY_GUARDED_END
|
|
*
|
|
* This macro, along with PCL_REENTRANCY_GUARDED_BEGIN, simplifies protection
|
|
* of non-reentrant code. See the AutoReentrancyGuard class for detailed
|
|
* information and examples.
|
|
*
|
|
* \ingroup reentrancy_protection
|
|
*/
|
|
#define PCL_REENTRANCY_GUARDED_END \
|
|
} \
|
|
}
|
|
|
|
/*!
|
|
* \def PCL_CLASS_REENTRANCY_GUARD
|
|
*
|
|
* Declares a class data member for class-wide protection of non-reentrant
|
|
* member functions with the PCL_CLASS_REENTRANCY_GUARDED_BEGIN and
|
|
* PCL_REENTRANCY_GUARDED_END macros.
|
|
*
|
|
* Example:
|
|
*
|
|
* \code class foo
|
|
* {
|
|
* public:
|
|
* // ...
|
|
* private:
|
|
* PCL_CLASS_REENTRANCY_GUARD
|
|
*
|
|
* void bar1()
|
|
* {
|
|
* PCL_CLASS_REENTRANCY_GUARDED_BEGIN
|
|
* // Protected code
|
|
* PCL_REENTRANCY_GUARDED_END
|
|
* }
|
|
*
|
|
* void bar2() const
|
|
* {
|
|
* PCL_CLASS_REENTRANCY_GUARDED_BEGIN
|
|
* // Protected code
|
|
* PCL_REENTRANCY_GUARDED_END
|
|
* }
|
|
* }; \endcode
|
|
*
|
|
* In this example the bar1 and bar2 member functions are protected against
|
|
* reentrant execution. Note that reentrancy protection is a per-instance,
|
|
* class-wide property in this case: the bar1() and bar2() functions can be
|
|
* executed simultaneously for different objects, but they cannot be re-entered
|
|
* for the same instance. Furthermore, one of these functions cannot call the
|
|
* other for the same object, since both share the same reentrancy guard member
|
|
* in the foo class.
|
|
*
|
|
* See the AutoReentrancyGuard class for more information on the PCL
|
|
* implementation of reentrancy protection.
|
|
*
|
|
* \ingroup reentrancy_protection
|
|
*/
|
|
#define PCL_CLASS_REENTRANCY_GUARD \
|
|
mutable pcl::AtomicInt __pcl_guard__;
|
|
|
|
/*!
|
|
* \def PCL_CLASS_REENTRANCY_GUARDED_BEGIN
|
|
*
|
|
* This macro, along with PCL_CLASS_REENTRANCY_GUARD and
|
|
* PCL_REENTRANCY_GUARDED_END, simplifies per-instance protection of
|
|
* non-reentrant class member functions. See PCL_CLASS_REENTRANCY_GUARD for an
|
|
* example.
|
|
*
|
|
* See the AutoReentrancyGuard class for more information on the PCL
|
|
* implementation of reentrancy protection.
|
|
*
|
|
* \ingroup reentrancy_protection
|
|
*/
|
|
#define PCL_CLASS_REENTRANCY_GUARDED_BEGIN \
|
|
{ \
|
|
volatile pcl::AutoReentrancyGuard __a_r_g__( __pcl_guard__ ); \
|
|
if ( __a_r_g__ ) \
|
|
{
|
|
|
|
/*!
|
|
* \def PCL_MEMBER_REENTRANCY_GUARD
|
|
*
|
|
* Declares a class data member for protection of a specific non-reentrant
|
|
* member function with the PCL_MEMBER_REENTRANCY_GUARDED_BEGIN and
|
|
* PCL_REENTRANCY_GUARDED_END macros.
|
|
*
|
|
* Example:
|
|
*
|
|
* \code class foo
|
|
* {
|
|
* public:
|
|
* // ...
|
|
* private:
|
|
* PCL_MEMBER_REENTRANCY_GUARD( bar1 )
|
|
* PCL_MEMBER_REENTRANCY_GUARD( bar2 )
|
|
*
|
|
* void bar1()
|
|
* {
|
|
* PCL_MEMBER_REENTRANCY_GUARDED_BEGIN( bar1 )
|
|
* // Protected code
|
|
* PCL_REENTRANCY_GUARDED_END
|
|
* }
|
|
*
|
|
* void bar2() const
|
|
* {
|
|
* PCL_MEMBER_REENTRANCY_GUARDED_BEGIN( bar2 )
|
|
* // Protected code
|
|
* PCL_REENTRANCY_GUARDED_END
|
|
* }
|
|
* }; \endcode
|
|
*
|
|
* In this example the bar1 and bar2 member functions are protected against
|
|
* reentrant execution. Note that reentrancy protection is a per-instance,
|
|
* function-specific property in this case: the bar1() and bar2() functions can
|
|
* be executed simultaneously for different objects, but they cannot be
|
|
* re-entered for the same instance. Since each member function uses its own
|
|
* reentrancy guard member in the foo class, each of them can safely call the
|
|
* other for the same object.
|
|
*
|
|
* See the AutoReentrancyGuard class for more information on the PCL
|
|
* implementation of reentrancy protection.
|
|
*
|
|
* \ingroup reentrancy_protection
|
|
*/
|
|
#define PCL_MEMBER_REENTRANCY_GUARD( member ) \
|
|
mutable pcl::AtomicInt __pcl_guard_##member##__;
|
|
|
|
/*!
|
|
* \def PCL_MEMBER_REENTRANCY_GUARDED_BEGIN
|
|
*
|
|
* This macro, along with PCL_MEMBER_REENTRANCY_GUARD and
|
|
* PCL_REENTRANCY_GUARDED_END, simplifies per-instance protection of specific
|
|
* non-reentrant member functions. See PCL_MEMBER_REENTRANCY_GUARD for an
|
|
* example.
|
|
*
|
|
* See the AutoReentrancyGuard class for more information on the PCL
|
|
* implementation of reentrancy protection.
|
|
*
|
|
* \ingroup reentrancy_protection
|
|
*/
|
|
#define PCL_MEMBER_REENTRANCY_GUARDED_BEGIN( member ) \
|
|
{ \
|
|
volatile pcl::AutoReentrancyGuard __a_r_g__( __pcl_guard_##member##__ );\
|
|
if ( __a_r_g__ ) \
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
} // pcl
|
|
|
|
#endif // __PCL_Atomic_h
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// EOF pcl/Atomic.h - Released 2022-03-12T18:59:29Z
|