mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-09 13:22:24 +03:00
0029935: Foundation Classes - introduce OSD_ThreadPool class defining a thread pool
This commit is contained in:
@@ -120,7 +120,7 @@ void BRepMesh_FastDiscret::Perform(const TopoDS_Shape& theShape)
|
||||
aFaces.push_back(aFace);
|
||||
}
|
||||
|
||||
OSD_Parallel::ForEach(aFaces.begin(), aFaces.end(), *this, !myParameters.InParallel);
|
||||
OSD_Parallel::ForEach(aFaces.begin(), aFaces.end(), *this, !myParameters.InParallel, (Standard_Integer )aFaces.size());
|
||||
}
|
||||
|
||||
|
||||
|
@@ -234,7 +234,7 @@ void BRepMesh_IncrementalMesh::update()
|
||||
update(aFaceIt.Value());
|
||||
|
||||
// Mesh faces
|
||||
OSD_Parallel::ForEach(myFaces.begin(), myFaces.end(), *myMesh, !myParameters.InParallel);
|
||||
OSD_Parallel::ForEach(myFaces.begin(), myFaces.end(), *myMesh, !myParameters.InParallel, myFaces.Size());
|
||||
|
||||
commit();
|
||||
clear();
|
||||
|
@@ -57,6 +57,8 @@ OSD_OpenMode.hxx
|
||||
OSD_OSDError.hxx
|
||||
OSD_Parallel.cxx
|
||||
OSD_Parallel.hxx
|
||||
OSD_Parallel_TBB.cxx
|
||||
OSD_Parallel_Threads.cxx
|
||||
OSD_Path.cxx
|
||||
OSD_Path.hxx
|
||||
OSD_PerfMeter.cxx
|
||||
@@ -83,6 +85,8 @@ OSD_SingleProtection.hxx
|
||||
OSD_SysType.hxx
|
||||
OSD_Thread.cxx
|
||||
OSD_Thread.hxx
|
||||
OSD_ThreadPool.cxx
|
||||
OSD_ThreadPool.hxx
|
||||
OSD_ThreadFunction.hxx
|
||||
OSD_Timer.cxx
|
||||
OSD_Timer.hxx
|
||||
|
@@ -104,7 +104,10 @@ public:
|
||||
//! user's code. Refer to Foundation Classes User's Guide for further details.
|
||||
//!
|
||||
Standard_EXPORT static void SetSignal (const Standard_Boolean theFloatingSignal = Standard_True);
|
||||
|
||||
|
||||
//! Return floating signal catching value previously set by SetSignal().
|
||||
Standard_EXPORT static Standard_Boolean ToCatchFloatingSignals();
|
||||
|
||||
//! Commands the process to sleep for a number of seconds.
|
||||
Standard_EXPORT static void SecSleep (const Standard_Integer aDelay);
|
||||
|
||||
|
@@ -14,25 +14,25 @@
|
||||
#ifndef OSD_Parallel_HeaderFile
|
||||
#define OSD_Parallel_HeaderFile
|
||||
|
||||
#include <OSD_Thread.hxx>
|
||||
#include <Standard_Mutex.hxx>
|
||||
#include <Standard_NotImplemented.hxx>
|
||||
#include <Standard_Atomic.hxx>
|
||||
#include <NCollection_Array1.hxx>
|
||||
#include <Standard_Type.hxx>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef HAVE_TBB
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_for_each.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
#endif
|
||||
|
||||
//! @class OSD_Parallel
|
||||
//! @brief Simplifies code parallelization.
|
||||
//! @brief Simple tool for code parallelization.
|
||||
//!
|
||||
//! The Class provides an interface of parallel processing "for" and "foreach" loops.
|
||||
//! These primitives encapsulates complete logic for creating and managing parallel context of loops.
|
||||
//! Moreover the primitives may be a wrapper for some primitives from 3rd-party library - TBB.
|
||||
//! To use it is necessary to implement TBB like interface which is based on functors.
|
||||
//! OSD_Parallel class provides simple interface for parallel processing of
|
||||
//! tasks that can be formulated in terms of "for" or "foreach" loops.
|
||||
//!
|
||||
//! To use this tool it is necessary to:
|
||||
//! - organize the data to be processed in a collection accessible by
|
||||
//! iteration (usually array or vector);
|
||||
//! - implement a functor class providing operator () accepting iterator
|
||||
//! (or index in array) that does the job;
|
||||
//! - call either For() or ForEach() providing begin and end iterators and
|
||||
//! a functor object.
|
||||
//!
|
||||
//! Iterators should satisfy requirements of STL forward iterator.
|
||||
//! Functor
|
||||
//!
|
||||
//! @code
|
||||
//! class Functor
|
||||
@@ -45,268 +45,290 @@
|
||||
//! };
|
||||
//! @endcode
|
||||
//!
|
||||
//! In the body of the operator () should be implemented thread-safe logic of computations that can be performed in parallel context.
|
||||
//! If parallelized loop iterates on the collections with direct access by index (such as Vector, Array),
|
||||
//! it is more efficient to use the primitive ParallelFor (because it has no critical section).
|
||||
//! The operator () should be implemented in a thread-safe way so that
|
||||
//! the same functor object can process different data items in parallel threads.
|
||||
//!
|
||||
//! Iteration by index (For) is expected to be more efficient than using iterators
|
||||
//! (ForEach).
|
||||
//!
|
||||
//! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
|
||||
//! uses ad-hoc parallelization tool. In general, if TBB is available, it is
|
||||
//! more efficient to use it directly instead of using OSD_Parallel.
|
||||
|
||||
class OSD_Parallel
|
||||
{
|
||||
//! Auxiliary class which ensures exclusive
|
||||
//! access to iterators of processed data pool.
|
||||
template <typename Value>
|
||||
class Range
|
||||
private:
|
||||
|
||||
//! Interface class defining API for polymorphic wrappers over iterators.
|
||||
//! Intended to add polymorphic behaviour to For and ForEach functionality
|
||||
//! for arbitrary objects and eliminate dependency on template parameters.
|
||||
class IteratorInterface
|
||||
{
|
||||
public: //! @name public methods
|
||||
public:
|
||||
virtual ~IteratorInterface() {}
|
||||
|
||||
typedef Value Iterator;
|
||||
//! Returns true if iterators wrapped by this and theOther are equal
|
||||
virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
|
||||
|
||||
//! Constructor
|
||||
Range(const Value& theBegin, const Value& theEnd)
|
||||
: myBegin(theBegin),
|
||||
myEnd (theEnd),
|
||||
myIt (theBegin)
|
||||
{
|
||||
}
|
||||
//! Increments wrapped iterator
|
||||
virtual void Increment () = 0;
|
||||
|
||||
//! Returns const link on the first element.
|
||||
inline const Value& Begin() const
|
||||
{
|
||||
return myBegin;
|
||||
}
|
||||
|
||||
//! Returns const link on the last element.
|
||||
inline const Value& End() const
|
||||
{
|
||||
return myEnd;
|
||||
}
|
||||
|
||||
//! Returns first non processed element or end.
|
||||
//! Thread-safe method.
|
||||
inline Iterator It() const
|
||||
{
|
||||
Standard_Mutex::Sentry aMutex( myMutex );
|
||||
return ( myIt != myEnd ) ? myIt++ : myEnd;
|
||||
}
|
||||
|
||||
private: //! @name private methods
|
||||
|
||||
//! Empty copy constructor
|
||||
Range(const Range& theCopy);
|
||||
|
||||
//! Empty copy operator.
|
||||
Range& operator=(const Range& theCopy);
|
||||
|
||||
private: //! @name private fields
|
||||
|
||||
const Value& myBegin; //!< Fisrt element of range.
|
||||
const Value& myEnd; //!< Last element of range.
|
||||
mutable Value myIt; //!< First non processed element of range.
|
||||
mutable Standard_Mutex myMutex; //!< Access controller for the first non processed element.
|
||||
//! Returns new instance of the wrapper containing copy
|
||||
//! of the wrapped iterator.
|
||||
virtual IteratorInterface* Clone() const = 0;
|
||||
};
|
||||
|
||||
//! Auxiliary wrapper class for thread function.
|
||||
template <typename Functor, typename InputIterator>
|
||||
class Task
|
||||
//! Implementation of polymorphic iterator wrapper suitable for basic
|
||||
//! types as well as for std iterators.
|
||||
//! Wraps instance of actual iterator type Type.
|
||||
template<class Type>
|
||||
class IteratorWrapper : public IteratorInterface
|
||||
{
|
||||
public: //! @name public methods
|
||||
public:
|
||||
IteratorWrapper() {}
|
||||
IteratorWrapper(const Type& theValue) : myValue(theValue) {}
|
||||
|
||||
//! Constructor.
|
||||
Task(const Functor& thePerformer, Range<InputIterator>& theRange)
|
||||
: myPerformer(thePerformer),
|
||||
myRange (theRange)
|
||||
virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
|
||||
{
|
||||
return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
|
||||
}
|
||||
|
||||
//! Method is executed in the context of thread,
|
||||
//! so this method defines the main calculations.
|
||||
static Standard_Address RunWithIterator(Standard_Address theTask)
|
||||
virtual void Increment () Standard_OVERRIDE
|
||||
{
|
||||
Task<Functor, InputIterator>& aTask =
|
||||
*( static_cast< Task<Functor, InputIterator>* >(theTask) );
|
||||
|
||||
const Range<InputIterator>& aData( aTask.myRange );
|
||||
typename Range<InputIterator>::Iterator i = aData.It();
|
||||
|
||||
for ( ; i != aData.End(); i = aData.It() )
|
||||
{
|
||||
aTask.myPerformer(*i);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
++myValue;
|
||||
}
|
||||
|
||||
//! Method is executed in the context of thread,
|
||||
//! so this method defines the main calculations.
|
||||
static Standard_Address RunWithIndex(Standard_Address theTask)
|
||||
virtual IteratorInterface* Clone() const Standard_OVERRIDE
|
||||
{
|
||||
Task<Functor, InputIterator>& aTask =
|
||||
*( static_cast< Task<Functor, Standard_Integer>* >(theTask) );
|
||||
|
||||
const Range<Standard_Integer>& aData( aTask.myRange );
|
||||
Standard_Integer i = aData.It();
|
||||
|
||||
for ( ; i < aData.End(); i = aData.It())
|
||||
{
|
||||
aTask.myPerformer(i);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return new IteratorWrapper<Type>(myValue);
|
||||
}
|
||||
|
||||
private: //! @name private methods
|
||||
const Type& Value() const { return myValue; }
|
||||
|
||||
//! Empty copy constructor.
|
||||
Task(const Task& theCopy);
|
||||
|
||||
//! Empty copy operator.
|
||||
Task& operator=(const Task& theCopy);
|
||||
|
||||
private: //! @name private fields
|
||||
|
||||
const Functor& myPerformer; //!< Link on functor.
|
||||
const Range<InputIterator>& myRange; //!< Link on processed data block.
|
||||
private:
|
||||
Type myValue;
|
||||
};
|
||||
|
||||
public: //! @name public methods
|
||||
protected:
|
||||
// Note: UniversalIterator and FunctorInterface are made protected to be
|
||||
// accessible from specialization using threads (non-TBB).
|
||||
|
||||
//! Returns number of logical proccesrs.
|
||||
Standard_EXPORT static Standard_Integer NbLogicalProcessors();
|
||||
//! Fixed-type iterator, implementing STL forward iterator interface, used for
|
||||
//! iteration over objects subject to parallel processing.
|
||||
//! It stores pointer to instance of polymorphic iterator inheriting from
|
||||
//! IteratorInterface, which contains actual type-specific iterator.
|
||||
class UniversalIterator :
|
||||
// Note that TBB requires that value_type of iterator be copyable,
|
||||
// thus we use its own type for that
|
||||
public std::iterator<std::forward_iterator_tag, UniversalIterator, ptrdiff_t, UniversalIterator*, UniversalIterator&>
|
||||
{
|
||||
public:
|
||||
UniversalIterator() {}
|
||||
|
||||
UniversalIterator(IteratorInterface* theOther)
|
||||
: myPtr(theOther)
|
||||
{
|
||||
}
|
||||
|
||||
UniversalIterator(const UniversalIterator& theOther)
|
||||
: myPtr (theOther.myPtr->Clone())
|
||||
{
|
||||
}
|
||||
|
||||
UniversalIterator& operator= (const UniversalIterator& theOther)
|
||||
{
|
||||
myPtr.reset (theOther.myPtr->Clone());
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator!= (const UniversalIterator& theOther) const
|
||||
{
|
||||
return ! myPtr->IsEqual (*theOther.myPtr);
|
||||
}
|
||||
|
||||
bool operator== (const UniversalIterator& theOther) const
|
||||
{
|
||||
return myPtr->IsEqual (*theOther.myPtr);
|
||||
}
|
||||
|
||||
UniversalIterator& operator++()
|
||||
{
|
||||
myPtr->Increment();
|
||||
return *this;
|
||||
}
|
||||
|
||||
UniversalIterator operator++(int)
|
||||
{
|
||||
UniversalIterator aValue(*this);
|
||||
myPtr->Increment();
|
||||
return aValue;
|
||||
}
|
||||
|
||||
const UniversalIterator& operator* () const { return *this; }
|
||||
UniversalIterator& operator* () { return *this; }
|
||||
|
||||
const UniversalIterator* operator->() const { return this; }
|
||||
UniversalIterator* operator->() { return this; }
|
||||
|
||||
// type cast to actual iterator
|
||||
template <typename Iterator>
|
||||
const Iterator& DownCast () const
|
||||
{
|
||||
return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(myPtr.get())->Value();
|
||||
}
|
||||
|
||||
private:
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
std::auto_ptr<IteratorInterface> myPtr;
|
||||
#else
|
||||
std::unique_ptr<IteratorInterface> myPtr;
|
||||
#endif
|
||||
};
|
||||
|
||||
//! Interface class representing functor object.
|
||||
//! Intended to add polymorphic behavour to For and ForEach functionality
|
||||
//! enabling execution of arbitrary function in parallel mode.
|
||||
class FunctorInterface
|
||||
{
|
||||
public:
|
||||
virtual ~FunctorInterface() {}
|
||||
|
||||
virtual void operator () (UniversalIterator& theIterator) const = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
//! Wrapper for functors manipulating on std iterators.
|
||||
template<class Iterator, class Functor>
|
||||
class FunctorWrapperIter : public FunctorInterface
|
||||
{
|
||||
public:
|
||||
FunctorWrapperIter (const Functor& theFunctor)
|
||||
: myFunctor(theFunctor)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
|
||||
{
|
||||
const Iterator& anIt = theIterator.DownCast<Iterator>();
|
||||
myFunctor(*anIt);
|
||||
}
|
||||
|
||||
private:
|
||||
FunctorWrapperIter (const FunctorWrapperIter&);
|
||||
void operator = (const FunctorWrapperIter&);
|
||||
const Functor& myFunctor;
|
||||
};
|
||||
|
||||
//! Wrapper for functors manipulating on integer index.
|
||||
template<class Functor>
|
||||
class FunctorWrapperInt : public FunctorInterface
|
||||
{
|
||||
public:
|
||||
FunctorWrapperInt (const Functor& theFunctor)
|
||||
: myFunctor(theFunctor)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void operator() (UniversalIterator& theIterator) const Standard_OVERRIDE
|
||||
{
|
||||
Standard_Integer anIndex = theIterator.DownCast<Standard_Integer>();
|
||||
myFunctor(anIndex);
|
||||
}
|
||||
|
||||
private:
|
||||
FunctorWrapperInt (const FunctorWrapperInt&);
|
||||
void operator = (const FunctorWrapperInt&);
|
||||
const Functor& myFunctor;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
//! Simple primitive for parallelization of "foreach" loops, e.g.:
|
||||
//! @code
|
||||
//! for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
|
||||
//! @endcode
|
||||
//! Implementation of framework-dependent functionality should be provided by
|
||||
//! forEach_impl function defined in opencascade::parallel namespace.
|
||||
//! @param theBegin the first index (incusive)
|
||||
//! @param theEnd the last index (exclusive)
|
||||
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}" performing task for specified iterator position
|
||||
//! @param isForceSingleThreadExecution if true, then no threads will be created
|
||||
template <typename InputIterator, typename Functor>
|
||||
static void ForEach( InputIterator theBegin,
|
||||
InputIterator theEnd,
|
||||
const Functor& theFunctor,
|
||||
const Standard_Boolean isForceSingleThreadExecution
|
||||
= Standard_False );
|
||||
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
|
||||
//! performing task for the specified iterator position
|
||||
//! @param theNbItems number of items passed by iterator, -1 if unknown
|
||||
Standard_EXPORT static void forEach (UniversalIterator& theBegin,
|
||||
UniversalIterator& theEnd,
|
||||
const FunctorInterface& theFunctor,
|
||||
Standard_Integer theNbItems);
|
||||
|
||||
//! Simple primitive for parallelization of "for" loops, e.g.:
|
||||
public: //! @name public methods
|
||||
|
||||
//! Returns number of logical proccesrs.
|
||||
Standard_EXPORT static Standard_Integer NbLogicalProcessors();
|
||||
|
||||
//! Simple primitive for parallelization of "foreach" loops, equivalent to:
|
||||
//! @code
|
||||
//! for (int anIter = theBegin; anIter < theEnd; ++anIter) {}
|
||||
//! for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
|
||||
//! theFunctor(*anIter);
|
||||
//! }
|
||||
//! @endcode
|
||||
//! @param theBegin the first index (incusive)
|
||||
//! @param theEnd the last index (exclusive)
|
||||
//! @param theFunctor functor providing an interface "void operator(int theIndex){}" performing task for specified index
|
||||
//! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
|
||||
//! performing task for specified iterator position
|
||||
//! @param isForceSingleThreadExecution if true, then no threads will be created
|
||||
//! @param theNbItems number of items passed by iterator, -1 if unknown
|
||||
template <typename InputIterator, typename Functor>
|
||||
static void ForEach(InputIterator theBegin,
|
||||
InputIterator theEnd,
|
||||
const Functor& theFunctor,
|
||||
const Standard_Boolean isForceSingleThreadExecution = Standard_False,
|
||||
Standard_Integer theNbItems = -1)
|
||||
{
|
||||
if (isForceSingleThreadExecution || theNbItems == 1)
|
||||
{
|
||||
for (InputIterator it(theBegin); it != theEnd; ++it)
|
||||
theFunctor(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
|
||||
UniversalIterator aEnd (new IteratorWrapper<InputIterator>(theEnd));
|
||||
FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
|
||||
forEach(aBegin, aEnd, aFunctor, theNbItems);
|
||||
}
|
||||
}
|
||||
|
||||
//! Simple primitive for parallelization of "for" loops, equivalent to:
|
||||
//! @code
|
||||
//! for (int anIter = theBegin; anIter != theEnd; ++anIter) {
|
||||
//! theFunctor(anIter);
|
||||
//! }
|
||||
//! @endcode
|
||||
//! @param theBegin the first index (incusive)
|
||||
//! @param theEnd the last index (exclusive)
|
||||
//! @param theFunctor functor providing an interface "void operator(int theIndex){}"
|
||||
//! performing task for specified index
|
||||
//! @param isForceSingleThreadExecution if true, then no threads will be created
|
||||
template <typename Functor>
|
||||
static void For( const Standard_Integer theBegin,
|
||||
const Standard_Integer theEnd,
|
||||
const Functor& theFunctor,
|
||||
const Standard_Boolean isForceSingleThreadExecution
|
||||
= Standard_False );
|
||||
static void For(const Standard_Integer theBegin,
|
||||
const Standard_Integer theEnd,
|
||||
const Functor& theFunctor,
|
||||
const Standard_Boolean isForceSingleThreadExecution = Standard_False)
|
||||
{
|
||||
if (isForceSingleThreadExecution || (theEnd - theBegin) == 1)
|
||||
{
|
||||
for (Standard_Integer it (theBegin); it != theEnd; ++it)
|
||||
theFunctor(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
|
||||
UniversalIterator aEnd (new IteratorWrapper<Standard_Integer>(theEnd));
|
||||
FunctorWrapperInt<Functor> aFunctor (theFunctor);
|
||||
forEach(aBegin, aEnd, aFunctor, theEnd - theBegin);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//=======================================================================
|
||||
//function : OSD_Parallel::Range::It
|
||||
//purpose : Template concretization.
|
||||
//=======================================================================
|
||||
template<> inline Standard_Integer OSD_Parallel::Range<Standard_Integer>::It() const
|
||||
{
|
||||
return Standard_Atomic_Increment( reinterpret_cast<volatile int*>(&myIt) ) - 1;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : ParallelForEach
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
template <typename InputIterator, typename Functor>
|
||||
void OSD_Parallel::ForEach( InputIterator theBegin,
|
||||
InputIterator theEnd,
|
||||
const Functor& theFunctor,
|
||||
const Standard_Boolean isForceSingleThreadExecution )
|
||||
{
|
||||
if ( isForceSingleThreadExecution )
|
||||
{
|
||||
for ( InputIterator it(theBegin); it != theEnd; ++it )
|
||||
theFunctor(*it);
|
||||
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_TBB
|
||||
{
|
||||
try
|
||||
{
|
||||
tbb::parallel_for_each(theBegin, theEnd, theFunctor);
|
||||
}
|
||||
catch ( tbb::captured_exception& anException )
|
||||
{
|
||||
throw Standard_NotImplemented(anException.what());
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
Range<InputIterator> aData(theBegin, theEnd);
|
||||
Task<Functor, InputIterator> aTask(theFunctor, aData);
|
||||
|
||||
const Standard_Integer aNbThreads = OSD_Parallel::NbLogicalProcessors();
|
||||
NCollection_Array1<OSD_Thread> aThreads(0, aNbThreads - 1);
|
||||
|
||||
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
|
||||
{
|
||||
OSD_Thread& aThread = aThreads(i);
|
||||
aThread.SetFunction(&Task<Functor, InputIterator>::RunWithIterator);
|
||||
aThread.Run(&aTask);
|
||||
}
|
||||
|
||||
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
|
||||
aThreads(i).Wait();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : ParallelFor
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
template <typename Functor>
|
||||
void OSD_Parallel::For( const Standard_Integer theBegin,
|
||||
const Standard_Integer theEnd,
|
||||
const Functor& theFunctor,
|
||||
const Standard_Boolean isForceSingleThreadExecution )
|
||||
{
|
||||
if ( isForceSingleThreadExecution )
|
||||
{
|
||||
for ( Standard_Integer i = theBegin; i < theEnd; ++i )
|
||||
theFunctor(i);
|
||||
|
||||
return;
|
||||
}
|
||||
#ifdef HAVE_TBB
|
||||
{
|
||||
try
|
||||
{
|
||||
tbb::parallel_for( theBegin, theEnd, theFunctor );
|
||||
}
|
||||
catch ( tbb::captured_exception& anException )
|
||||
{
|
||||
throw Standard_NotImplemented(anException.what());
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
Range<Standard_Integer> aData(theBegin, theEnd);
|
||||
Task<Functor, Standard_Integer> aTask(theFunctor, aData);
|
||||
|
||||
const Standard_Integer aNbThreads = OSD_Parallel::NbLogicalProcessors();
|
||||
NCollection_Array1<OSD_Thread> aThreads(0, aNbThreads - 1);
|
||||
|
||||
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
|
||||
{
|
||||
OSD_Thread& aThread = aThreads(i);
|
||||
aThread.SetFunction(&Task<Functor, Standard_Integer>::RunWithIndex);
|
||||
aThread.Run(&aTask);
|
||||
}
|
||||
|
||||
for ( Standard_Integer i = 0; i < aNbThreads; ++i )
|
||||
aThreads(i).Wait();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
48
src/OSD/OSD_Parallel_TBB.cxx
Normal file
48
src/OSD/OSD_Parallel_TBB.cxx
Normal file
@@ -0,0 +1,48 @@
|
||||
// Created on: 2014-08-19
|
||||
// Created by: Alexander Zaikin
|
||||
// Copyright (c) 1996-1999 Matra Datavision
|
||||
// Copyright (c) 2013-2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
// Version of parallel executor used when TBB is available
|
||||
#ifdef HAVE_TBB
|
||||
|
||||
#include <OSD_Parallel.hxx>
|
||||
#include <Standard_ProgramError.hxx>
|
||||
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/parallel_for_each.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
|
||||
//=======================================================================
|
||||
//function : forEach
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
|
||||
void OSD_Parallel::forEach (UniversalIterator& theBegin,
|
||||
UniversalIterator& theEnd,
|
||||
const FunctorInterface& theFunctor,
|
||||
Standard_Integer theNbItems)
|
||||
{
|
||||
(void )theNbItems;
|
||||
try
|
||||
{
|
||||
tbb::parallel_for_each(theBegin, theEnd, theFunctor);
|
||||
}
|
||||
catch (tbb::captured_exception& anException)
|
||||
{
|
||||
throw Standard_ProgramError(anException.what());
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_TBB */
|
159
src/OSD/OSD_Parallel_Threads.cxx
Normal file
159
src/OSD/OSD_Parallel_Threads.cxx
Normal file
@@ -0,0 +1,159 @@
|
||||
// Created on: 2014-08-19
|
||||
// Created by: Alexander Zaikin
|
||||
// Copyright (c) 1996-1999 Matra Datavision
|
||||
// Copyright (c) 2013-2014 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
// Version of parallel executor used when TBB is not available
|
||||
#ifndef HAVE_TBB
|
||||
|
||||
#include <OSD_Parallel.hxx>
|
||||
|
||||
#include <OSD_ThreadPool.hxx>
|
||||
|
||||
#include <NCollection_Array1.hxx>
|
||||
#include <Standard_Mutex.hxx>
|
||||
#include <OSD_Thread.hxx>
|
||||
|
||||
namespace
|
||||
{
|
||||
//! Class implementing tools for parallel processing
|
||||
//! using threads (when TBB is not available);
|
||||
//! it is derived from OSD_Parallel to get access to
|
||||
//! Iterator and FunctorInterface nested types.
|
||||
class OSD_Parallel_Threads : public OSD_ThreadPool, public OSD_Parallel
|
||||
{
|
||||
public:
|
||||
//! Auxiliary class which ensures exclusive
|
||||
//! access to iterators of processed data pool.
|
||||
class Range
|
||||
{
|
||||
public: //! @name public methods
|
||||
|
||||
//! Constructor
|
||||
Range(const OSD_Parallel::UniversalIterator& theBegin,
|
||||
const OSD_Parallel::UniversalIterator& theEnd)
|
||||
: myBegin(theBegin),
|
||||
myEnd(theEnd),
|
||||
myIt(theBegin)
|
||||
{
|
||||
}
|
||||
|
||||
//! Returns const link on the first element.
|
||||
inline const OSD_Parallel::UniversalIterator& Begin() const
|
||||
{
|
||||
return myBegin;
|
||||
}
|
||||
|
||||
//! Returns const link on the last element.
|
||||
inline const OSD_Parallel::UniversalIterator& End() const
|
||||
{
|
||||
return myEnd;
|
||||
}
|
||||
|
||||
//! Returns first non processed element or end.
|
||||
//! Thread-safe method.
|
||||
inline OSD_Parallel::UniversalIterator It() const
|
||||
{
|
||||
Standard_Mutex::Sentry aMutex(myMutex);
|
||||
return (myIt != myEnd) ? myIt++ : myEnd;
|
||||
}
|
||||
|
||||
private: //! @name private methods
|
||||
|
||||
//! Empty copy constructor
|
||||
Range(const Range& theCopy);
|
||||
|
||||
//! Empty copy operator.
|
||||
Range& operator=(const Range& theCopy);
|
||||
|
||||
private: //! @name private fields
|
||||
|
||||
const OSD_Parallel::UniversalIterator& myBegin; //!< Fisrt element of range.
|
||||
const OSD_Parallel::UniversalIterator& myEnd; //!< Last element of range.
|
||||
mutable OSD_Parallel::UniversalIterator myIt; //!< First non processed element of range.
|
||||
mutable Standard_Mutex myMutex; //!< Access controller for the first non processed element.
|
||||
};
|
||||
|
||||
//! Auxiliary wrapper class for thread function.
|
||||
class Task : public JobInterface
|
||||
{
|
||||
public: //! @name public methods
|
||||
|
||||
//! Constructor.
|
||||
Task(const OSD_Parallel::FunctorInterface& thePerformer, Range& theRange)
|
||||
: myPerformer(thePerformer),
|
||||
myRange(theRange)
|
||||
{
|
||||
}
|
||||
|
||||
//! Method is executed in the context of thread,
|
||||
//! so this method defines the main calculations.
|
||||
virtual void Perform (int ) Standard_OVERRIDE
|
||||
{
|
||||
for (OSD_Parallel::UniversalIterator anIter = myRange.It(); anIter != myRange.End(); anIter = myRange.It())
|
||||
{
|
||||
myPerformer (anIter);
|
||||
}
|
||||
}
|
||||
|
||||
private: //! @name private methods
|
||||
|
||||
//! Empty copy constructor.
|
||||
Task(const Task& theCopy);
|
||||
|
||||
//! Empty copy operator.
|
||||
Task& operator=(const Task& theCopy);
|
||||
|
||||
private: //! @name private fields
|
||||
const FunctorInterface& myPerformer; //!< Link on functor
|
||||
const Range& myRange; //!< Link on processed data block
|
||||
};
|
||||
|
||||
//! Launcher specialization.
|
||||
class UniversalLauncher : public Launcher
|
||||
{
|
||||
public:
|
||||
//! Constructor.
|
||||
UniversalLauncher (OSD_ThreadPool& thePool, int theMaxThreads = -1)
|
||||
: Launcher (thePool, theMaxThreads) {}
|
||||
|
||||
//! Primitive for parallelization of "for" loops.
|
||||
void Perform (OSD_Parallel::UniversalIterator& theBegin,
|
||||
OSD_Parallel::UniversalIterator& theEnd,
|
||||
const OSD_Parallel::FunctorInterface& theFunctor)
|
||||
{
|
||||
Range aData (theBegin, theEnd);
|
||||
Task aJob (theFunctor, aData);
|
||||
perform (aJob);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
//function : forEach
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
void OSD_Parallel::forEach (UniversalIterator& theBegin,
|
||||
UniversalIterator& theEnd,
|
||||
const FunctorInterface& theFunctor,
|
||||
Standard_Integer theNbItems)
|
||||
{
|
||||
const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
|
||||
const Standard_Integer aNbThreads = theNbItems != -1 ? Min (theNbItems, aThreadPool->NbDefaultThreadsToLaunch()) : -1;
|
||||
OSD_Parallel_Threads::UniversalLauncher aLauncher (*aThreadPool, aNbThreads);
|
||||
aLauncher.Perform (theBegin, theEnd, theFunctor);
|
||||
}
|
||||
|
||||
#endif /* ! HAVE_TBB */
|
401
src/OSD/OSD_ThreadPool.cxx
Normal file
401
src/OSD/OSD_ThreadPool.cxx
Normal file
@@ -0,0 +1,401 @@
|
||||
// Created by: Kirill Gavrilov
|
||||
// Copyright (c) 2017 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of commercial software by OPEN CASCADE SAS.
|
||||
//
|
||||
// This software is furnished in accordance with the terms and conditions
|
||||
// of the contract and with the inclusion of this copyright notice.
|
||||
// This software or any other copy thereof may not be provided or otherwise
|
||||
// be made available to any third party.
|
||||
// No ownership title to the software is transferred hereby.
|
||||
//
|
||||
// OPEN CASCADE SAS makes no representation or warranties with respect to the
|
||||
// performance of this software, and specifically disclaims any responsibility
|
||||
// for any damages, special or consequential, connected with its use.
|
||||
|
||||
#include <OSD_ThreadPool.hxx>
|
||||
|
||||
#include <OSD.hxx>
|
||||
#include <Standard_Atomic.hxx>
|
||||
#include <TCollection_AsciiString.hxx>
|
||||
|
||||
IMPLEMENT_STANDARD_RTTIEXT(OSD_ThreadPool, Standard_Transient)
|
||||
|
||||
// =======================================================================
|
||||
// function : Lock
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool OSD_ThreadPool::EnumeratedThread::Lock()
|
||||
{
|
||||
return Standard_Atomic_CompareAndSwap (&myUsageCounter, 0, 1);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Free
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::EnumeratedThread::Free()
|
||||
{
|
||||
Standard_Atomic_CompareAndSwap (&myUsageCounter, 1, 0);
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : WakeUp
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::EnumeratedThread::WakeUp (JobInterface* theJob, bool theToCatchFpe)
|
||||
{
|
||||
myJob = theJob;
|
||||
myToCatchFpe = theToCatchFpe;
|
||||
if (myIsSelfThread)
|
||||
{
|
||||
if (theJob != NULL)
|
||||
{
|
||||
OSD_ThreadPool::performJob (myFailure, myJob, myThreadIndex);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
myWakeEvent.Set();
|
||||
if (theJob != NULL && !myIsStarted)
|
||||
{
|
||||
myIsStarted = true;
|
||||
Run (this);
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : WaitIdle
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::EnumeratedThread::WaitIdle()
|
||||
{
|
||||
if (!myIsSelfThread)
|
||||
{
|
||||
myIdleEvent.Wait();
|
||||
myIdleEvent.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : DefaultPool
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
const Handle(OSD_ThreadPool)& OSD_ThreadPool::DefaultPool (int theNbThreads)
|
||||
{
|
||||
static const Handle(OSD_ThreadPool) THE_GLOBAL_POOL = new OSD_ThreadPool (theNbThreads);
|
||||
return THE_GLOBAL_POOL;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : OSD_ThreadPool
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
OSD_ThreadPool::OSD_ThreadPool (int theNbThreads)
|
||||
: myNbDefThreads (0),
|
||||
myShutDown (false)
|
||||
{
|
||||
Init (theNbThreads);
|
||||
myNbDefThreads = NbThreads();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : IsInUse
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool OSD_ThreadPool::IsInUse()
|
||||
{
|
||||
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More(); aThreadIter.Next())
|
||||
{
|
||||
EnumeratedThread& aThread = aThreadIter.ChangeValue();
|
||||
if (!aThread.Lock())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
aThread.Free();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Init
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::Init (int theNbThreads)
|
||||
{
|
||||
const int aNbThreads = Max (0, (theNbThreads > 0 ? theNbThreads : OSD_Parallel::NbLogicalProcessors()) - 1);
|
||||
if (myThreads.Size() == aNbThreads)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// release old threads
|
||||
if (!myThreads.IsEmpty())
|
||||
{
|
||||
NCollection_Array1<EnumeratedThread*> aLockThreads (myThreads.Lower(), myThreads.Upper());
|
||||
aLockThreads.Init (NULL);
|
||||
int aThreadIndex = myThreads.Lower();
|
||||
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More(); aThreadIter.Next())
|
||||
{
|
||||
EnumeratedThread& aThread = aThreadIter.ChangeValue();
|
||||
if (!aThread.Lock())
|
||||
{
|
||||
for (NCollection_Array1<EnumeratedThread*>::Iterator aLockThreadIter (aLockThreads);
|
||||
aLockThreadIter.More() && aLockThreadIter.Value() != NULL; aLockThreadIter.Next())
|
||||
{
|
||||
aLockThreadIter.ChangeValue()->Free();
|
||||
}
|
||||
throw Standard_ProgramError ("Error: active ThreadPool is reinitialized");
|
||||
}
|
||||
aLockThreads.SetValue (aThreadIndex++, &aThread);
|
||||
}
|
||||
}
|
||||
release();
|
||||
|
||||
myShutDown = false;
|
||||
if (aNbThreads > 0)
|
||||
{
|
||||
myThreads.Resize (0, aNbThreads - 1, false);
|
||||
int aLastThreadIndex = 0;
|
||||
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More(); aThreadIter.Next())
|
||||
{
|
||||
EnumeratedThread& aThread = aThreadIter.ChangeValue();
|
||||
aThread.myPool = this;
|
||||
aThread.myThreadIndex = aLastThreadIndex++;
|
||||
aThread.SetFunction (&OSD_ThreadPool::EnumeratedThread::runThread);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
NCollection_Array1<EnumeratedThread> anEmpty;
|
||||
myThreads.Move (anEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ~OSD_ThreadPool
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
OSD_ThreadPool::~OSD_ThreadPool()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : release
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::release()
|
||||
{
|
||||
if (myThreads.IsEmpty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
myShutDown = true;
|
||||
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More(); aThreadIter.Next())
|
||||
{
|
||||
aThreadIter.ChangeValue().WakeUp (NULL, false);
|
||||
aThreadIter.ChangeValue().Wait();
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : perform
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::Launcher::perform (JobInterface& theJob)
|
||||
{
|
||||
run (theJob);
|
||||
wait();
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : run
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::Launcher::run (JobInterface& theJob)
|
||||
{
|
||||
bool toCatchFpe = OSD::ToCatchFloatingSignals();
|
||||
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
|
||||
{
|
||||
aThreadIter.ChangeValue()->WakeUp (&theJob, toCatchFpe);
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : wait
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::Launcher::wait()
|
||||
{
|
||||
int aNbFailures = 0;
|
||||
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
|
||||
{
|
||||
aThreadIter.ChangeValue()->WaitIdle();
|
||||
if (!aThreadIter.Value()->myFailure.IsNull())
|
||||
{
|
||||
++aNbFailures;
|
||||
}
|
||||
}
|
||||
if (aNbFailures == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TCollection_AsciiString aFailures;
|
||||
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
|
||||
{
|
||||
if (!aThreadIter.Value()->myFailure.IsNull())
|
||||
{
|
||||
if (aNbFailures == 1)
|
||||
{
|
||||
aThreadIter.Value()->myFailure->Reraise();
|
||||
}
|
||||
|
||||
if (!aFailures.IsEmpty())
|
||||
{
|
||||
aFailures += "\n";
|
||||
}
|
||||
aFailures += aThreadIter.Value()->myFailure->GetMessageString();
|
||||
}
|
||||
}
|
||||
|
||||
aFailures = TCollection_AsciiString("Multiple exceptions:\n") + aFailures;
|
||||
throw Standard_ProgramError (aFailures.ToCString());
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : performJob
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::performJob (Handle(Standard_Failure)& theFailure,
|
||||
OSD_ThreadPool::JobInterface* theJob,
|
||||
int theThreadIndex)
|
||||
{
|
||||
try
|
||||
{
|
||||
OCC_CATCH_SIGNALS
|
||||
theJob->Perform (theThreadIndex);
|
||||
}
|
||||
catch (Standard_Failure const& aFailure)
|
||||
{
|
||||
TCollection_AsciiString aMsg = TCollection_AsciiString (aFailure.DynamicType()->Name())
|
||||
+ ": " + aFailure.GetMessageString();
|
||||
theFailure = new Standard_ProgramError (aMsg.ToCString());
|
||||
}
|
||||
catch (std::exception& anStdException)
|
||||
{
|
||||
TCollection_AsciiString aMsg = TCollection_AsciiString (typeid(anStdException).name())
|
||||
+ ": " + anStdException.what();
|
||||
theFailure = new Standard_ProgramError (aMsg.ToCString());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
theFailure = new Standard_ProgramError ("Error: Unknown exception");
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : performThread
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::EnumeratedThread::performThread()
|
||||
{
|
||||
OSD::SetSignal (false);
|
||||
for (;;)
|
||||
{
|
||||
myWakeEvent.Wait();
|
||||
myWakeEvent.Reset();
|
||||
if (myPool->myShutDown)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
myFailure.Nullify();
|
||||
if (myJob != NULL)
|
||||
{
|
||||
OSD::SetSignal (myToCatchFpe);
|
||||
OSD_ThreadPool::performJob (myFailure, myJob, myThreadIndex);
|
||||
myJob = NULL;
|
||||
}
|
||||
myIdleEvent.Set();
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : runThread
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Address OSD_ThreadPool::EnumeratedThread::runThread (Standard_Address theTask)
|
||||
{
|
||||
EnumeratedThread* aThread = static_cast<EnumeratedThread*>(theTask);
|
||||
aThread->performThread();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Launcher
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
OSD_ThreadPool::Launcher::Launcher (OSD_ThreadPool& thePool, Standard_Integer theMaxThreads)
|
||||
: mySelfThread (true),
|
||||
myNbThreads (0)
|
||||
{
|
||||
const int aNbThreads = theMaxThreads > 0
|
||||
? Min (theMaxThreads, thePool.NbThreads())
|
||||
: (theMaxThreads < 0
|
||||
? Max (thePool.NbDefaultThreadsToLaunch(), 1)
|
||||
: 1);
|
||||
myThreads.Resize (0, aNbThreads - 1, false);
|
||||
myThreads.Init (NULL);
|
||||
if (aNbThreads > 1)
|
||||
{
|
||||
for (NCollection_Array1<EnumeratedThread>::Iterator aThreadIter (thePool.myThreads);
|
||||
aThreadIter.More(); aThreadIter.Next())
|
||||
{
|
||||
if (aThreadIter.ChangeValue().Lock())
|
||||
{
|
||||
myThreads.SetValue (myNbThreads, &aThreadIter.ChangeValue());
|
||||
// make thread index to fit into myThreads range
|
||||
aThreadIter.ChangeValue().myThreadIndex = myNbThreads;
|
||||
if (++myNbThreads == aNbThreads - 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// self thread should be executed last
|
||||
myThreads.SetValue (myNbThreads, &mySelfThread);
|
||||
mySelfThread.myThreadIndex = myNbThreads;
|
||||
++myNbThreads;
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Release
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void OSD_ThreadPool::Launcher::Release()
|
||||
{
|
||||
for (NCollection_Array1<EnumeratedThread*>::Iterator aThreadIter (myThreads);
|
||||
aThreadIter.More() && aThreadIter.Value() != NULL; aThreadIter.Next())
|
||||
{
|
||||
if (aThreadIter.Value() != &mySelfThread)
|
||||
{
|
||||
aThreadIter.Value()->Free();
|
||||
}
|
||||
}
|
||||
|
||||
NCollection_Array1<EnumeratedThread*> anEmpty;
|
||||
myThreads.Move (anEmpty);
|
||||
myNbThreads = 0;
|
||||
}
|
301
src/OSD/OSD_ThreadPool.hxx
Normal file
301
src/OSD/OSD_ThreadPool.hxx
Normal file
@@ -0,0 +1,301 @@
|
||||
// Created by: Kirill Gavrilov
|
||||
// Copyright (c) 2017 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of commercial software by OPEN CASCADE SAS.
|
||||
//
|
||||
// This software is furnished in accordance with the terms and conditions
|
||||
// of the contract and with the inclusion of this copyright notice.
|
||||
// This software or any other copy thereof may not be provided or otherwise
|
||||
// be made available to any third party.
|
||||
// No ownership title to the software is transferred hereby.
|
||||
//
|
||||
// OPEN CASCADE SAS makes no representation or warranties with respect to the
|
||||
// performance of this software, and specifically disclaims any responsibility
|
||||
// for any damages, special or consequential, connected with its use.
|
||||
|
||||
#ifndef _OSD_ThreadPool_HeaderFile
|
||||
#define _OSD_ThreadPool_HeaderFile
|
||||
|
||||
#include <NCollection_Array1.hxx>
|
||||
#include <OSD_Thread.hxx>
|
||||
#include <OSD_Parallel.hxx>
|
||||
#include <Standard_Atomic.hxx>
|
||||
#include <Standard_Condition.hxx>
|
||||
#include <Standard_Mutex.hxx>
|
||||
|
||||
//! Class defining a thread pool for executing algorithms in multi-threaded mode.
|
||||
//! Thread pool allocates requested amount of threads and keep them alive
|
||||
//! (in sleep mode when unused) during thread pool lifetime.
|
||||
//! The same pool can be used by multiple consumers,
|
||||
//! including nested multi-threading algorithms and concurrent threads:
|
||||
//! - Thread pool can be used either by multi-threaded algorithm by creating OSD_ThreadPool::Launcher.
|
||||
//! The functor performing a job takes two parameters - Thread Index and Data Index:
|
||||
//! void operator(int theThreadIndex, int theDataIndex){}
|
||||
//! Multi-threaded algorithm may rely on Thread Index for allocating thread-local variables in array form,
|
||||
//! since the Thread Index is guaranteed to be within range OSD_ThreadPool::Lower() and OSD_ThreadPool::Upper().
|
||||
//! - Default thread pool (OSD_ThreadPool::DefaultPool()) can be used in general case,
|
||||
//! but application may prefer creating a dedicated pool for better control.
|
||||
//! - Default thread pool allocates the amount of threads considering concurrency
|
||||
//! level of the system (amount of logical processors).
|
||||
//! This can be overridden during OSD_ThreadPool construction or by calling OSD_ThreadPool::Init()
|
||||
//! (the pool should not be used!).
|
||||
//! - OSD_ThreadPool::Launcher reserves specific amount of threads from the pool for executing multi-threaded Job.
|
||||
//! Normally, single Launcher instance will occupy all threads available in thread pool,
|
||||
//! so that nested multi-threaded algorithms (within the same thread)
|
||||
//! and concurrent threads trying to use the same thread pool will run sequentially.
|
||||
//! This behavior is affected by OSD_ThreadPool::NbDefaultThreadsToLaunch() parameter
|
||||
//! and Launcher constructor, so that single Launcher instance will occupy not all threads
|
||||
//! in the pool allowing other threads to be used concurrently.
|
||||
//! - OSD_ThreadPool::Launcher locks thread one-by-one from thread pool in a thread-safe way.
|
||||
//! - Each working thread catches exceptions occurred during job execution, and Launcher will
|
||||
//! throw Standard_Failure in a caller thread on completed execution.
|
||||
class OSD_ThreadPool : public Standard_Transient
|
||||
{
|
||||
DEFINE_STANDARD_RTTIEXT(OSD_ThreadPool, Standard_Transient)
|
||||
public:
|
||||
|
||||
//! Return (or create) a default thread pool.
|
||||
//! Number of threads argument will be considered only when called first time.
|
||||
Standard_EXPORT static const Handle(OSD_ThreadPool)& DefaultPool (int theNbThreads = -1);
|
||||
|
||||
public:
|
||||
|
||||
//! Main constructor.
|
||||
//! Application may consider specifying more threads than actually
|
||||
//! available (OSD_Parallel::NbLogicalProcessors()) and set up NbDefaultThreadsToLaunch() to a smaller value
|
||||
//! so that concurrent threads will be able using single Thread Pool instance more efficiently.
|
||||
//! @param theNbThreads threads number to be created by pool
|
||||
//! (if -1 is specified then OSD_Parallel::NbLogicalProcessors() will be used)
|
||||
Standard_EXPORT OSD_ThreadPool (int theNbThreads = -1);
|
||||
|
||||
//! Destructor.
|
||||
Standard_EXPORT virtual ~OSD_ThreadPool();
|
||||
|
||||
//! Return TRUE if at least 2 threads are available (including self-thread).
|
||||
bool HasThreads() const { return NbThreads() >= 2; }
|
||||
|
||||
//! Return the lower thread index.
|
||||
int LowerThreadIndex() const { return 0; }
|
||||
|
||||
//! Return the upper thread index (last index is reserved for self-thread).
|
||||
int UpperThreadIndex() const { return LowerThreadIndex() + myThreads.Size(); }
|
||||
|
||||
//! Return the number of threads; >= 1.
|
||||
int NbThreads() const { return myThreads.Size() + 1; }
|
||||
|
||||
//! Return maximum number of threads to be locked by a single Launcher object by default;
|
||||
//! the entire thread pool size is returned by default.
|
||||
int NbDefaultThreadsToLaunch() const { return myNbDefThreads; }
|
||||
|
||||
//! Set maximum number of threads to be locked by a single Launcher object by default.
|
||||
//! Should be set BEFORE first usage.
|
||||
void SetNbDefaultThreadsToLaunch (int theNbThreads) { myNbDefThreads = theNbThreads; }
|
||||
|
||||
//! Checks if thread pools has active consumers.
|
||||
Standard_EXPORT bool IsInUse();
|
||||
|
||||
//! Reinitialize the thread pool with a different number of threads.
|
||||
//! Should be called only with no active jobs, or exception Standard_ProgramError will be thrown!
|
||||
Standard_EXPORT void Init (int theNbThreads);
|
||||
|
||||
protected:
|
||||
|
||||
//! Thread function interface.
|
||||
class JobInterface
|
||||
{
|
||||
public:
|
||||
virtual void Perform (int theThreadIndex) = 0;
|
||||
};
|
||||
|
||||
//! Thread with back reference to thread pool and thread index in it.
|
||||
class EnumeratedThread : public OSD_Thread
|
||||
{
|
||||
friend class OSD_ThreadPool;
|
||||
public:
|
||||
EnumeratedThread (bool theIsSelfThread = false)
|
||||
: myPool (NULL), myJob (NULL), myWakeEvent (false),
|
||||
myIdleEvent (false), myThreadIndex (0), myUsageCounter(0),
|
||||
myIsStarted (false), myToCatchFpe (false),
|
||||
myIsSelfThread (theIsSelfThread) {}
|
||||
|
||||
//! Occupy this thread for thread pool launcher.
|
||||
//! @return TRUE on success, or FALSE if thread has been already occupied
|
||||
Standard_EXPORT bool Lock();
|
||||
|
||||
//! Release this thread for thread pool launcher; should be called only after successful OccupyThread().
|
||||
Standard_EXPORT void Free();
|
||||
|
||||
//! Wake up the thread.
|
||||
Standard_EXPORT void WakeUp (JobInterface* theJob, bool theToCatchFpe);
|
||||
|
||||
//! Wait the thread going into Idle state (finished jobs).
|
||||
Standard_EXPORT void WaitIdle();
|
||||
|
||||
private:
|
||||
|
||||
//! Method is executed in the context of thread.
|
||||
void performThread();
|
||||
|
||||
//! Method is executed in the context of thread.
|
||||
static Standard_Address runThread (Standard_Address theTask);
|
||||
|
||||
private:
|
||||
OSD_ThreadPool* myPool;
|
||||
JobInterface* myJob;
|
||||
Handle(Standard_Failure) myFailure;
|
||||
Standard_Condition myWakeEvent;
|
||||
Standard_Condition myIdleEvent;
|
||||
int myThreadIndex;
|
||||
volatile int myUsageCounter;
|
||||
bool myIsStarted;
|
||||
bool myToCatchFpe;
|
||||
bool myIsSelfThread;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
//! Launcher object locking a subset of threads (or all threads)
|
||||
//! in a thread pool to perform parallel execution of the job.
|
||||
class Launcher
|
||||
{
|
||||
public:
|
||||
//! Lock specified number of threads from the thread pool.
|
||||
//! If thread pool is already locked by another user,
|
||||
//! Launcher will lock as many threads as possible
|
||||
//! (if none will be locked, then single threaded execution will be done).
|
||||
//! @param thePool thread pool to lock the threads
|
||||
//! @param theMaxThreads number of threads to lock;
|
||||
//! -1 specifies that default number of threads
|
||||
//! to be used OSD_ThreadPool::NbDefaultThreadsToLaunch()
|
||||
Standard_EXPORT Launcher (OSD_ThreadPool& thePool, int theMaxThreads = -1);
|
||||
|
||||
//! Release threads.
|
||||
~Launcher() { Release(); }
|
||||
|
||||
//! Return TRUE if at least 2 threads have been locked for parallel execution (including self-thread);
|
||||
//! otherwise, the functor will be executed within the caller thread.
|
||||
bool HasThreads() const { return myNbThreads >= 2; }
|
||||
|
||||
//! Return amount of locked threads; >= 1.
|
||||
int NbThreads() const { return myNbThreads; }
|
||||
|
||||
//! Return the lower thread index.
|
||||
int LowerThreadIndex() const { return 0; }
|
||||
|
||||
//! Return the upper thread index (last index is reserved for the self-thread).
|
||||
int UpperThreadIndex() const { return LowerThreadIndex() + myNbThreads - 1; }
|
||||
|
||||
//! Simple primitive for parallelization of "for" loops, e.g.:
|
||||
//! @code
|
||||
//! for (int anIter = theBegin; anIter < theEnd; ++anIter) {}
|
||||
//! @endcode
|
||||
//! @param theBegin the first data index (inclusive)
|
||||
//! @param theEnd the last data index (exclusive)
|
||||
//! @param theFunctor functor providing an interface
|
||||
//! "void operator(int theThreadIndex, int theDataIndex){}" performing task for specified index
|
||||
template<typename Functor>
|
||||
void Perform (int theBegin, int theEnd, const Functor& theFunctor)
|
||||
{
|
||||
JobRange aData (theBegin, theEnd);
|
||||
Job<Functor> aJob (theFunctor, aData);
|
||||
perform (aJob);
|
||||
}
|
||||
|
||||
//! Release threads before Launcher destruction.
|
||||
Standard_EXPORT void Release();
|
||||
|
||||
protected:
|
||||
|
||||
//! Execute job.
|
||||
Standard_EXPORT void perform (JobInterface& theJob);
|
||||
|
||||
//! Initialize job and start threads.
|
||||
Standard_EXPORT void run (JobInterface& theJob);
|
||||
|
||||
//! Wait threads execution.
|
||||
Standard_EXPORT void wait();
|
||||
|
||||
private:
|
||||
Launcher (const Launcher& theCopy);
|
||||
Launcher& operator=(const Launcher& theCopy);
|
||||
|
||||
private:
|
||||
NCollection_Array1<EnumeratedThread*> myThreads; //!< array of locked threads (including self-thread)
|
||||
EnumeratedThread mySelfThread;
|
||||
int myNbThreads; //!< amount of locked threads
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
//! Auxiliary class which ensures exclusive access to iterators of processed data pool.
|
||||
class JobRange
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
JobRange (const int& theBegin, const int& theEnd) : myBegin(theBegin), myEnd (theEnd), myIt (theBegin) {}
|
||||
|
||||
//! Returns const link on the first element.
|
||||
const int& Begin() const { return myBegin; }
|
||||
|
||||
//! Returns const link on the last element.
|
||||
const int& End() const { return myEnd; }
|
||||
|
||||
//! Returns first non processed element or end.
|
||||
//! Thread-safe method.
|
||||
int It() const { return Standard_Atomic_Increment (reinterpret_cast<volatile int*>(&myIt)) - 1; }
|
||||
|
||||
private:
|
||||
JobRange (const JobRange& theCopy);
|
||||
JobRange& operator=(const JobRange& theCopy);
|
||||
|
||||
private:
|
||||
const int& myBegin; //!< First element of range
|
||||
const int& myEnd; //!< Last element of range
|
||||
mutable int myIt; //!< First non processed element of range
|
||||
};
|
||||
|
||||
//! Auxiliary wrapper class for thread function.
|
||||
template<typename FunctorT> class Job : public JobInterface
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructor.
|
||||
Job (const FunctorT& thePerformer, JobRange& theRange)
|
||||
: myPerformer (thePerformer), myRange (theRange) {}
|
||||
|
||||
//! Method is executed in the context of thread.
|
||||
virtual void Perform (int theThreadIndex) Standard_OVERRIDE
|
||||
{
|
||||
for (Standard_Integer anIter = myRange.It(); anIter < myRange.End(); anIter = myRange.It())
|
||||
{
|
||||
myPerformer (theThreadIndex, anIter);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Job (const Job& theCopy);
|
||||
Job& operator=(const Job& theCopy);
|
||||
|
||||
private: //! @name private fields
|
||||
const FunctorT& myPerformer; //!< Link on functor
|
||||
const JobRange& myRange; //!< Link on processed data block
|
||||
};
|
||||
|
||||
//! Release threads.
|
||||
void release();
|
||||
|
||||
//! Perform the job and catch exceptions.
|
||||
static void performJob (Handle(Standard_Failure)& theFailure,
|
||||
OSD_ThreadPool::JobInterface* theJob,
|
||||
int theThreadIndex);
|
||||
|
||||
private:
|
||||
|
||||
NCollection_Array1<EnumeratedThread> myThreads; //!< array of defined threads (excluding self-thread)
|
||||
int myNbDefThreads; //!< maximum number of threads to be locked by a single Launcher by default
|
||||
bool myShutDown; //!< flag to shut down (destroy) the thread pool
|
||||
|
||||
};
|
||||
|
||||
#endif // _OSD_ThreadPool_HeaderFile
|
@@ -17,6 +17,17 @@
|
||||
#include <Standard_DivideByZero.hxx>
|
||||
#include <Standard_Overflow.hxx>
|
||||
|
||||
static Standard_THREADLOCAL Standard_Boolean fFltExceptions = Standard_False;
|
||||
|
||||
//=======================================================================
|
||||
//function : ToCatchFloatingSignals
|
||||
//purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean OSD::ToCatchFloatingSignals()
|
||||
{
|
||||
return fFltExceptions;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
//---------------------------- Windows NT System --------------------------------
|
||||
|
||||
@@ -53,7 +64,7 @@
|
||||
#include <Standard_ProgramError.hxx>
|
||||
#include <Standard_Mutex.hxx>
|
||||
|
||||
#include <OSD_WNT_1.hxx>
|
||||
#include <OSD_WNT.hxx>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <eh.h>
|
||||
@@ -65,10 +76,8 @@
|
||||
#include <float.h>
|
||||
|
||||
static Standard_Boolean fCtrlBrk;
|
||||
#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
|
||||
|
||||
static Standard_Boolean fMsgBox;
|
||||
static Standard_Boolean fFltExceptions;
|
||||
static Standard_Boolean fDbgLoaded;
|
||||
|
||||
// used to forbid simultaneous execution of setting / executing handlers
|
||||
static Standard_Mutex THE_SIGNAL_MUTEX;
|
||||
@@ -76,13 +85,20 @@ static Standard_Mutex THE_SIGNAL_MUTEX;
|
||||
static LONG __fastcall _osd_raise ( DWORD, LPSTR );
|
||||
static BOOL WINAPI _osd_ctrl_break_handler ( DWORD );
|
||||
|
||||
#ifndef OCCT_UWP
|
||||
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
|
||||
static Standard_Boolean fDbgLoaded;
|
||||
static LONG _osd_debug ( void );
|
||||
#endif
|
||||
|
||||
//# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW | _EM_UNDERFLOW )
|
||||
# define _OSD_FPX ( _EM_INVALID | _EM_DENORMAL | _EM_ZERODIVIDE | _EM_OVERFLOW )
|
||||
|
||||
#ifdef OCC_CONVERT_SIGNALS
|
||||
#define THROW_OR_JUMP(Type,Message) Type::NewInstance(Message)->Jump()
|
||||
#else
|
||||
#define THROW_OR_JUMP(Type,Message) throw Type(Message)
|
||||
#endif
|
||||
|
||||
//=======================================================================
|
||||
//function : CallHandler
|
||||
//purpose :
|
||||
@@ -148,7 +164,8 @@ static LONG CallHandler (DWORD dwExceptionCode,
|
||||
break ;
|
||||
case STATUS_NO_MEMORY:
|
||||
// cout << "CallHandler : STATUS_NO_MEMORY:" << endl ;
|
||||
throw OSD_Exception_STATUS_NO_MEMORY ( "MEMORY ALLOCATION ERROR ( no room in the process heap )" );
|
||||
THROW_OR_JUMP (OSD_Exception_STATUS_NO_MEMORY, "MEMORY ALLOCATION ERROR ( no room in the process heap )");
|
||||
break;
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
// cout << "CallHandler : EXCEPTION_ACCESS_VIOLATION:" << endl ;
|
||||
StringCchPrintfW (buffer, _countof(buffer), L"%s%s%s0x%.8p%s%s%s", L"ACCESS VIOLATION",
|
||||
@@ -227,7 +244,7 @@ static LONG CallHandler (DWORD dwExceptionCode,
|
||||
_fpreset();
|
||||
_clearfp();
|
||||
|
||||
#ifndef OCCT_UWP
|
||||
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
|
||||
MessageBeep ( MB_ICONHAND );
|
||||
int aChoice = ::MessageBoxW (0, buffer, L"OCCT Exception Handler", MB_ABORTRETRYIGNORE | MB_ICONSTOP);
|
||||
if (aChoice == IDRETRY)
|
||||
@@ -287,7 +304,7 @@ static void SIGWntHandler (int signum, int sub_code)
|
||||
break ;
|
||||
default:
|
||||
cout << "SIGWntHandler(default) -> throw Standard_NumericError(\"Floating Point Error\");" << endl;
|
||||
throw Standard_NumericError("Floating Point Error");
|
||||
THROW_OR_JUMP (Standard_NumericError, "Floating Point Error");
|
||||
break ;
|
||||
}
|
||||
break ;
|
||||
@@ -309,7 +326,6 @@ static void SIGWntHandler (int signum, int sub_code)
|
||||
DebugBreak ();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
//=======================================================================
|
||||
//function : TranslateSE
|
||||
@@ -342,7 +358,6 @@ static void TranslateSE( unsigned int theCode, EXCEPTION_POINTERS* theExcPtr )
|
||||
// option and unless user sets his own exception handler with
|
||||
// ::SetUnhandledExceptionFilter().
|
||||
//=======================================================================
|
||||
#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
|
||||
static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
|
||||
{
|
||||
DWORD dwExceptionCode = lpXP->ExceptionRecord->ExceptionCode;
|
||||
@@ -351,7 +366,6 @@ static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
|
||||
lpXP->ExceptionRecord->ExceptionInformation[1],
|
||||
lpXP->ExceptionRecord->ExceptionInformation[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
//=======================================================================
|
||||
//function : SetSignal
|
||||
@@ -359,11 +373,8 @@ static LONG WINAPI WntHandler (EXCEPTION_POINTERS *lpXP)
|
||||
//=======================================================================
|
||||
void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
|
||||
{
|
||||
#if !defined(__CYGWIN32__) && !defined(__MINGW32__)
|
||||
Standard_Mutex::Sentry aSentry (THE_SIGNAL_MUTEX); // lock the mutex to prevent simultaneous handling
|
||||
#if !defined(OCCT_UWP) || defined(NTDDI_WIN10_TH2)
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER aPreviousFilter;
|
||||
|
||||
OSD_Environment env ("CSF_DEBUG_MODE");
|
||||
TCollection_AsciiString val = env.Value();
|
||||
if (!env.Failed())
|
||||
@@ -380,7 +391,7 @@ void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
|
||||
// when user's code is compiled with /EHs
|
||||
// Replaces the existing top-level exception filter for all existing and all future threads
|
||||
// in the calling process
|
||||
aPreviousFilter = ::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
|
||||
::SetUnhandledExceptionFilter (/*(LPTOP_LEVEL_EXCEPTION_FILTER)*/ WntHandler);
|
||||
#endif // NTDDI_WIN10_TH2
|
||||
|
||||
// Signal handlers will only be used when the method ::raise() will be used
|
||||
@@ -410,7 +421,6 @@ void OSD::SetSignal (const Standard_Boolean theFloatingSignal)
|
||||
else {
|
||||
_controlfp (_OSD_FPX, _OSD_FPX); // JR add :
|
||||
}
|
||||
#endif
|
||||
} // end OSD :: SetSignal
|
||||
|
||||
//============================================================================
|
||||
@@ -422,7 +432,7 @@ void OSD::ControlBreak () {
|
||||
throw OSD_Exception_CTRL_BREAK ( "*** INTERRUPT ***" );
|
||||
}
|
||||
} // end OSD :: ControlBreak
|
||||
#if !defined(__MINGW32__) && !defined(__CYGWIN32__)
|
||||
|
||||
#ifndef OCCT_UWP
|
||||
//============================================================================
|
||||
//==== _osd_ctrl_break_handler
|
||||
@@ -437,6 +447,7 @@ static BOOL WINAPI _osd_ctrl_break_handler ( DWORD dwCode ) {
|
||||
return TRUE;
|
||||
} // end _osd_ctrl_break_handler
|
||||
#endif
|
||||
|
||||
//============================================================================
|
||||
//==== _osd_raise
|
||||
//============================================================================
|
||||
@@ -447,54 +458,54 @@ static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
|
||||
switch (dwCode)
|
||||
{
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
throw OSD_Exception_ACCESS_VIOLATION(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_ACCESS_VIOLATION, msg);
|
||||
break;
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
throw OSD_Exception_ARRAY_BOUNDS_EXCEEDED(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_ARRAY_BOUNDS_EXCEEDED, msg);
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
throw Standard_ProgramError(msg);
|
||||
THROW_OR_JUMP (Standard_ProgramError, msg);
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
throw OSD_Exception_ILLEGAL_INSTRUCTION(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_ILLEGAL_INSTRUCTION, msg);
|
||||
break;
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
throw OSD_Exception_IN_PAGE_ERROR(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_IN_PAGE_ERROR, msg);
|
||||
break;
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
throw Standard_DivideByZero(msg);
|
||||
THROW_OR_JUMP (Standard_DivideByZero, msg);
|
||||
break;
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
throw OSD_Exception_INT_OVERFLOW(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_INT_OVERFLOW, msg);
|
||||
break;
|
||||
case EXCEPTION_INVALID_DISPOSITION:
|
||||
throw OSD_Exception_INVALID_DISPOSITION(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_INVALID_DISPOSITION, msg);
|
||||
break;
|
||||
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
|
||||
throw OSD_Exception_NONCONTINUABLE_EXCEPTION(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_NONCONTINUABLE_EXCEPTION, msg);
|
||||
break;
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
throw OSD_Exception_PRIV_INSTRUCTION(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_PRIV_INSTRUCTION, msg);
|
||||
break;
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
throw OSD_Exception_STACK_OVERFLOW(msg);
|
||||
THROW_OR_JUMP (OSD_Exception_STACK_OVERFLOW, msg);
|
||||
break;
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
throw Standard_DivideByZero(msg);
|
||||
THROW_OR_JUMP (Standard_DivideByZero, msg);
|
||||
break;
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
throw Standard_Overflow(msg);
|
||||
THROW_OR_JUMP (Standard_Overflow, msg);
|
||||
break;
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
throw Standard_Underflow(msg);
|
||||
THROW_OR_JUMP (Standard_Underflow, msg);
|
||||
break;
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
case STATUS_FLOAT_MULTIPLE_TRAPS:
|
||||
case STATUS_FLOAT_MULTIPLE_FAULTS:
|
||||
throw Standard_NumericError(msg);
|
||||
THROW_OR_JUMP (Standard_NumericError, msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -502,10 +513,10 @@ static LONG __fastcall _osd_raise ( DWORD dwCode, LPSTR msg )
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
} // end _osd_raise
|
||||
|
||||
#if ! defined(OCCT_UWP) && !defined(__MINGW32__) && !defined(__CYGWIN32__)
|
||||
//============================================================================
|
||||
//==== _osd_debug
|
||||
//============================================================================
|
||||
#ifndef OCCT_UWP
|
||||
LONG _osd_debug ( void ) {
|
||||
|
||||
LONG action ;
|
||||
@@ -588,10 +599,9 @@ LONG _osd_debug ( void ) {
|
||||
return action ;
|
||||
|
||||
} // end _osd_debug
|
||||
#endif /* ! OCCT_UWP && ! __CYGWIN__ && ! __MINGW32__ */
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#else /* ! _WIN32 */
|
||||
|
||||
//---------- All Systems except Windows NT : ----------------------------------
|
||||
|
||||
@@ -616,7 +626,6 @@ LONG _osd_debug ( void ) {
|
||||
#ifdef __linux__
|
||||
#include <cfenv>
|
||||
//#include <fenv.h>
|
||||
static Standard_Boolean fFltExceptions = Standard_False;
|
||||
#endif
|
||||
|
||||
// variable signalling that Control-C has been pressed (SIGINT signal)
|
||||
@@ -635,7 +644,7 @@ typedef void (* SIG_PFV) (int);
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
#else
|
||||
# ifdef SA_SIGINFO
|
||||
# ifdef SA_SIGINFO
|
||||
# ifndef _AIX
|
||||
# include <sys/siginfo.h>
|
||||
# endif
|
||||
@@ -866,11 +875,11 @@ static void SegvHandler(const int theSignal,
|
||||
#endif
|
||||
|
||||
//============================================================================
|
||||
//==== SetSignal
|
||||
//==== SetSignal
|
||||
//==== Set the differents signals:
|
||||
//============================================================================
|
||||
|
||||
void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
{
|
||||
struct sigaction act, oact;
|
||||
int stat = 0;
|
||||
@@ -932,7 +941,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
#endif
|
||||
|
||||
//==== Always detected the signal "SIGFPE" =================================
|
||||
stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception
|
||||
stat = sigaction(SIGFPE,&act,&oact); // ...... floating point exception
|
||||
if (stat) {
|
||||
#ifdef OCCT_DEBUG
|
||||
cerr << "sigaction does not work !!! KO " << endl;
|
||||
@@ -941,38 +950,38 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
}
|
||||
|
||||
//==== Detected the only the "free" signals ================================
|
||||
sigaction(SIGHUP,&act,&oact); // ...... hangup
|
||||
sigaction(SIGHUP,&act,&oact); // ...... hangup
|
||||
|
||||
#ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGHUP,&oact,&oact);
|
||||
#endif
|
||||
|
||||
sigaction(SIGINT,&act,&oact); // ...... interrupt
|
||||
sigaction(SIGINT,&act,&oact); // ...... interrupt
|
||||
|
||||
#ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGINT,&oact,&oact);
|
||||
#endif
|
||||
|
||||
|
||||
sigaction(SIGQUIT,&act,&oact); // ...... quit
|
||||
|
||||
#ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGQUIT,&oact,&oact);
|
||||
#endif
|
||||
|
||||
sigaction(SIGILL,&act,&oact); // ...... illegal instruction
|
||||
sigaction(SIGILL,&act,&oact); // ...... illegal instruction
|
||||
|
||||
#ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGILL,&oact,&oact);
|
||||
#endif
|
||||
|
||||
sigaction(SIGBUS,&act,&oact); // ...... bus error
|
||||
sigaction(SIGBUS,&act,&oact); // ...... bus error
|
||||
|
||||
#ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGBUS,&oact,&oact);
|
||||
#endif
|
||||
|
||||
@@ -980,7 +989,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
sigaction(SIGSYS,&act,&oact); // ...... bad argument to system call
|
||||
|
||||
# ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGSYS,&oact,&oact);
|
||||
# endif
|
||||
#endif
|
||||
@@ -989,7 +998,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
sigaction(SIGTRAP,&act,&oact); // Integer Divide By Zero (IRIX)
|
||||
|
||||
# ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGTRAP,&oact,&oact);
|
||||
# endif
|
||||
#endif
|
||||
@@ -1004,7 +1013,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
perror("OSD::SetSignal sigaction( SIGSEGV , &act , &oact ) ") ;
|
||||
|
||||
#ifdef OBJS
|
||||
if(oact.sa_handler)
|
||||
if(oact.sa_handler)
|
||||
sigaction(SIGSEGV,&oact,&oact);
|
||||
#endif
|
||||
#if defined(__osf__) || defined(DECOSF1)
|
||||
@@ -1012,7 +1021,7 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
action.sa_handler = SIG_IGN;
|
||||
action.sa_mask = 0;
|
||||
action.sa_flags = 0;
|
||||
|
||||
|
||||
if (sigaction (SIGFPE, &action, &prev_action) == -1) {
|
||||
perror ("sigaction");
|
||||
exit (1);
|
||||
@@ -1022,14 +1031,14 @@ void OSD::SetSignal(const Standard_Boolean aFloatingSignal)
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//==== ControlBreak
|
||||
//==== ControlBreak
|
||||
//============================================================================
|
||||
|
||||
void OSD :: ControlBreak ()
|
||||
void OSD :: ControlBreak ()
|
||||
{
|
||||
if ( fCtrlBrk ) {
|
||||
fCtrlBrk = Standard_False;
|
||||
throw OSD_Exception_CTRL_BREAK("*** INTERRUPT ***");
|
||||
throw OSD_Exception_CTRL_BREAK ("*** INTERRUPT ***");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -11,6 +11,8 @@ Standard_Byte.hxx
|
||||
Standard_Character.hxx
|
||||
Standard_CLocaleSentry.cxx
|
||||
Standard_CLocaleSentry.hxx
|
||||
Standard_Condition.cxx
|
||||
Standard_Condition.hxx
|
||||
Standard_ConstructionError.hxx
|
||||
Standard_Copy.tcl
|
||||
Standard_CString.cxx
|
||||
@@ -79,9 +81,9 @@ Standard_Real.hxx
|
||||
Standard_ShortReal.cxx
|
||||
Standard_ShortReal.hxx
|
||||
Standard_Size.hxx
|
||||
Standard_SStream.cxx
|
||||
Standard_SStream.hxx
|
||||
Standard_Stream.hxx
|
||||
Standard_Strtod.cxx
|
||||
Standard_ThreadId.hxx
|
||||
Standard_Time.hxx
|
||||
Standard_TooManyUsers.hxx
|
||||
@@ -92,7 +94,8 @@ Standard_Type.hxx
|
||||
Standard_TypeDef.hxx
|
||||
Standard_TypeMismatch.hxx
|
||||
Standard_Underflow.hxx
|
||||
Standard_UUID.cxx
|
||||
Standard_UUID.hxx
|
||||
Standard_values.h
|
||||
Standard_Version.hxx
|
||||
Standard_WarningsDisable.hxx
|
||||
Standard_WarningsRestore.hxx
|
@@ -35,6 +35,14 @@ inline int Standard_Atomic_Increment (volatile int* theValue);
|
||||
//! and returns resulting decremented value.
|
||||
inline int Standard_Atomic_Decrement (volatile int* theValue);
|
||||
|
||||
//! Perform an atomic compare and swap.
|
||||
//! That is, if the current value of *theValue is theOldValue, then write theNewValue into *theValue.
|
||||
//! @param theValue pointer to variable to modify
|
||||
//! @param theOldValue expected value to perform modification
|
||||
//! @param theNewValue new value to set in case if *theValue was equal to theOldValue
|
||||
//! @return TRUE if theNewValue has been set to *theValue
|
||||
inline bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue);
|
||||
|
||||
// Platform-dependent implementation
|
||||
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)
|
||||
// gcc explicitly defines the macros __GCC_HAVE_SYNC_COMPARE_AND_SWAP_*
|
||||
@@ -55,16 +63,23 @@ int Standard_Atomic_Decrement (volatile int* theValue)
|
||||
return __sync_sub_and_fetch (theValue, 1);
|
||||
}
|
||||
|
||||
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
|
||||
{
|
||||
return __sync_val_compare_and_swap (theValue, theOldValue, theNewValue) == theOldValue;
|
||||
}
|
||||
|
||||
#elif defined(_WIN32)
|
||||
extern "C" {
|
||||
long _InterlockedIncrement (volatile long* lpAddend);
|
||||
long _InterlockedDecrement (volatile long* lpAddend);
|
||||
long _InterlockedCompareExchange (long volatile* Destination, long Exchange, long Comparand);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_MSC_VER) && ! defined(__INTEL_COMPILER)
|
||||
// force intrinsic instead of WinAPI calls
|
||||
#pragma intrinsic (_InterlockedIncrement)
|
||||
#pragma intrinsic (_InterlockedDecrement)
|
||||
#pragma intrinsic (_InterlockedCompareExchange)
|
||||
#endif
|
||||
|
||||
// WinAPI function or MSVC intrinsic
|
||||
@@ -80,6 +95,11 @@ int Standard_Atomic_Decrement (volatile int* theValue)
|
||||
return _InterlockedDecrement (reinterpret_cast<volatile long*>(theValue));
|
||||
}
|
||||
|
||||
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
|
||||
{
|
||||
return _InterlockedCompareExchange (reinterpret_cast<volatile long*>(theValue), theNewValue, theOldValue) == theOldValue;
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
// use atomic operations provided by MacOS
|
||||
|
||||
@@ -95,6 +115,11 @@ int Standard_Atomic_Decrement (volatile int* theValue)
|
||||
return OSAtomicDecrement32Barrier (theValue);
|
||||
}
|
||||
|
||||
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
|
||||
{
|
||||
return OSAtomicCompareAndSwapInt (theOldValue, theNewValue, theValue);
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
|
||||
// Atomic operations that were exported by the C library didn't
|
||||
@@ -114,34 +139,9 @@ int Standard_Atomic_Decrement (volatile int* theValue)
|
||||
return __atomic_dec (theValue) - 1; // analog of __sync_fetch_and_sub
|
||||
}
|
||||
|
||||
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64))
|
||||
// use x86 / x86_64 inline assembly (compatibility with alien compilers / old GCC)
|
||||
|
||||
inline int Standard_Atomic_Add (volatile int* theValue, int theVal)
|
||||
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
|
||||
{
|
||||
// C equivalent:
|
||||
// *theValue += theVal;
|
||||
// return *theValue;
|
||||
|
||||
int previous;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock xadd %0,%1"
|
||||
: "=q"(previous), "=m"(*theValue) //output
|
||||
: "0"(theVal), "m"(*theValue) //input
|
||||
: "memory" //clobbers
|
||||
);
|
||||
return previous + theVal;
|
||||
}
|
||||
|
||||
int Standard_Atomic_Increment (volatile int* theValue)
|
||||
{
|
||||
return Standard_Atomic_Add (theValue, 1);
|
||||
}
|
||||
|
||||
int Standard_Atomic_Decrement (volatile int* theValue)
|
||||
{
|
||||
return Standard_Atomic_Add (theValue, -1);
|
||||
return __atomic_cmpxchg (theOldValue, theNewValue, theValue) == 0;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -159,6 +159,16 @@ int Standard_Atomic_Decrement (volatile int* theValue)
|
||||
return --(*theValue);
|
||||
}
|
||||
|
||||
bool Standard_Atomic_CompareAndSwap (volatile int* theValue, int theOldValue, int theNewValue)
|
||||
{
|
||||
if (*theValue == theOldValue)
|
||||
{
|
||||
*theValue = theNewValue;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif //_Standard_Atomic_HeaderFile
|
||||
|
207
src/Standard/Standard_Condition.cxx
Normal file
207
src/Standard/Standard_Condition.cxx
Normal file
@@ -0,0 +1,207 @@
|
||||
// Created by: Kirill Gavrilov
|
||||
// Copyright (c) 2018 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "Standard_Condition.hxx"
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifndef _WIN32
|
||||
//! clock_gettime() wrapper.
|
||||
static void conditionGetRealTime (struct timespec& theTime)
|
||||
{
|
||||
#if defined(__APPLE__)
|
||||
struct timeval aTime;
|
||||
gettimeofday (&aTime, NULL);
|
||||
theTime.tv_sec = aTime.tv_sec;
|
||||
theTime.tv_nsec = aTime.tv_usec * 1000;
|
||||
#else
|
||||
clock_gettime (CLOCK_REALTIME, &theTime);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Standard_Condition
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Condition::Standard_Condition (bool theIsSet)
|
||||
#ifdef _WIN32
|
||||
: myEvent((void* )::CreateEvent (0, true, theIsSet, NULL))
|
||||
#else
|
||||
: myFlag (theIsSet)
|
||||
#endif
|
||||
{
|
||||
#ifndef _WIN32
|
||||
pthread_mutex_init(&myMutex, 0);
|
||||
pthread_cond_init (&myCond, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : ~Standard_Condition
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
Standard_Condition::~Standard_Condition()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
::CloseHandle ((HANDLE )myEvent);
|
||||
#else
|
||||
pthread_mutex_destroy(&myMutex);
|
||||
pthread_cond_destroy (&myCond);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Set
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Standard_Condition::Set()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
::SetEvent ((HANDLE )myEvent);
|
||||
#else
|
||||
pthread_mutex_lock(&myMutex);
|
||||
myFlag = true;
|
||||
pthread_cond_broadcast(&myCond);
|
||||
pthread_mutex_unlock (&myMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Reset
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Standard_Condition::Reset()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
::ResetEvent ((HANDLE )myEvent);
|
||||
#else
|
||||
pthread_mutex_lock (&myMutex);
|
||||
myFlag = false;
|
||||
pthread_mutex_unlock (&myMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Wait
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
void Standard_Condition::Wait()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
::WaitForSingleObject ((HANDLE )myEvent, INFINITE);
|
||||
#else
|
||||
pthread_mutex_lock (&myMutex);
|
||||
if (!myFlag)
|
||||
{
|
||||
pthread_cond_wait (&myCond, &myMutex);
|
||||
}
|
||||
pthread_mutex_unlock (&myMutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Wait
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Standard_Condition::Wait (int theTimeMilliseconds)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )theTimeMilliseconds) != WAIT_TIMEOUT);
|
||||
#else
|
||||
bool isSignalled = true;
|
||||
pthread_mutex_lock (&myMutex);
|
||||
if (!myFlag)
|
||||
{
|
||||
struct timespec aNow;
|
||||
struct timespec aTimeout;
|
||||
conditionGetRealTime (aNow);
|
||||
aTimeout.tv_sec = (theTimeMilliseconds / 1000);
|
||||
aTimeout.tv_nsec = (theTimeMilliseconds - aTimeout.tv_sec * 1000) * 1000000;
|
||||
if (aTimeout.tv_nsec > 1000000000)
|
||||
{
|
||||
aTimeout.tv_sec += 1;
|
||||
aTimeout.tv_nsec -= 1000000000;
|
||||
}
|
||||
aTimeout.tv_sec += aNow.tv_sec;
|
||||
aTimeout.tv_nsec += aNow.tv_nsec;
|
||||
isSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
|
||||
}
|
||||
pthread_mutex_unlock (&myMutex);
|
||||
return isSignalled;
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : Check
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Standard_Condition::Check()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )0) != WAIT_TIMEOUT);
|
||||
#else
|
||||
bool isSignalled = true;
|
||||
pthread_mutex_lock (&myMutex);
|
||||
if (!myFlag)
|
||||
{
|
||||
struct timespec aNow;
|
||||
struct timespec aTimeout;
|
||||
conditionGetRealTime (aNow);
|
||||
aTimeout.tv_sec = aNow.tv_sec;
|
||||
aTimeout.tv_nsec = aNow.tv_nsec + 100;
|
||||
isSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
|
||||
}
|
||||
pthread_mutex_unlock (&myMutex);
|
||||
return isSignalled;
|
||||
#endif
|
||||
}
|
||||
|
||||
// =======================================================================
|
||||
// function : CheckReset
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
bool Standard_Condition::CheckReset()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const bool wasSignalled = (::WaitForSingleObject ((HANDLE )myEvent, (DWORD )0) != WAIT_TIMEOUT);
|
||||
::ResetEvent ((HANDLE )myEvent);
|
||||
return wasSignalled;
|
||||
#else
|
||||
pthread_mutex_lock (&myMutex);
|
||||
bool wasSignalled = myFlag;
|
||||
if (!myFlag)
|
||||
{
|
||||
struct timespec aNow;
|
||||
struct timespec aTimeout;
|
||||
conditionGetRealTime (aNow);
|
||||
aTimeout.tv_sec = aNow.tv_sec;
|
||||
aTimeout.tv_nsec = aNow.tv_nsec + 100;
|
||||
wasSignalled = (pthread_cond_timedwait (&myCond, &myMutex, &aTimeout) != ETIMEDOUT);
|
||||
}
|
||||
myFlag = false;
|
||||
pthread_mutex_unlock (&myMutex);
|
||||
return wasSignalled;
|
||||
#endif
|
||||
}
|
80
src/Standard/Standard_Condition.hxx
Normal file
80
src/Standard/Standard_Condition.hxx
Normal file
@@ -0,0 +1,80 @@
|
||||
// Created by: Kirill Gavrilov
|
||||
// Copyright (c) 2018 OPEN CASCADE SAS
|
||||
//
|
||||
// This file is part of Open CASCADE Technology software library.
|
||||
//
|
||||
// This library is free software; you can redistribute it and/or modify it under
|
||||
// the terms of the GNU Lesser General Public License version 2.1 as published
|
||||
// by the Free Software Foundation, with special exception defined in the file
|
||||
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
||||
// distribution for complete text of the license and disclaimer of any warranty.
|
||||
//
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#ifndef _Standard_Condition_HeaderFile
|
||||
#define _Standard_Condition_HeaderFile
|
||||
|
||||
#include <Standard.hxx>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
//! This is boolean flag intended for communication between threads.
|
||||
//! One thread sets this flag to TRUE to indicate some event happened
|
||||
//! and another thread either waits this event or checks periodically its state to perform job.
|
||||
//!
|
||||
//! This class provides interface similar to WinAPI Event objects.
|
||||
class Standard_Condition
|
||||
{
|
||||
public:
|
||||
|
||||
//! Default constructor.
|
||||
//! @param theIsSet Initial flag state
|
||||
Standard_EXPORT Standard_Condition (bool theIsSet);
|
||||
|
||||
//! Destructor.
|
||||
Standard_EXPORT ~Standard_Condition();
|
||||
|
||||
//! Set event into signaling state.
|
||||
Standard_EXPORT void Set();
|
||||
|
||||
//! Reset event (unset signaling state)
|
||||
Standard_EXPORT void Reset();
|
||||
|
||||
//! Wait for Event (infinity).
|
||||
Standard_EXPORT void Wait();
|
||||
|
||||
//! Wait for signal requested time.
|
||||
//! @param theTimeMilliseconds wait limit in milliseconds
|
||||
//! @return true if get event
|
||||
Standard_EXPORT bool Wait (int theTimeMilliseconds);
|
||||
|
||||
//! Do not wait for signal - just test it state.
|
||||
//! @return true if get event
|
||||
Standard_EXPORT bool Check();
|
||||
|
||||
//! Method perform two steps at-once - reset the event object
|
||||
//! and returns true if it was in signaling state.
|
||||
//! @return true if event object was in signaling state.
|
||||
Standard_EXPORT bool CheckReset();
|
||||
|
||||
#ifdef _WIN32
|
||||
//! Access native HANDLE to Event object.
|
||||
void* getHandle() const { return myEvent; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
#ifdef _WIN32
|
||||
void* myEvent;
|
||||
#else
|
||||
pthread_mutex_t myMutex;
|
||||
pthread_cond_t myCond;
|
||||
bool myFlag;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // _Standard_Condition_HeaderFile
|
@@ -58,23 +58,6 @@ static void deallocate_message(Standard_CString aMessage)
|
||||
}
|
||||
}
|
||||
|
||||
// Define Standard_THREADLOCAL modifier as C++11 thread_local keyword where it is available.
|
||||
#if defined(__clang__)
|
||||
// CLang version: standard CLang > 3.3 or XCode >= 8 (but excluding 32-bit ARM)
|
||||
// Note: this has to be in separate #if to avoid failure of preprocessor on other platforms
|
||||
#if __has_feature(cxx_thread_local)
|
||||
#define Standard_THREADLOCAL thread_local
|
||||
#else
|
||||
#define Standard_THREADLOCAL
|
||||
#endif
|
||||
#elif (defined(__INTEL_COMPILER) && __INTEL_COMPILER > 1400) || \
|
||||
(defined(_MSC_VER) && _MSC_VER >= 1900) /* MSVC++ >= 14 */ || \
|
||||
(defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) /* GCC >= 4.8 */
|
||||
#define Standard_THREADLOCAL thread_local
|
||||
#else
|
||||
#define Standard_THREADLOCAL
|
||||
#endif
|
||||
|
||||
// ******************************************************************
|
||||
// Standard_Failure *
|
||||
// ******************************************************************
|
||||
|
@@ -12,13 +12,21 @@
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
// Purpose: This file is intended to be the first file #included to any
|
||||
// Open CASCADE source. It defines platform-specific pre-processor
|
||||
// macros necessary for correct compilation of Open CASCADE code
|
||||
//! @file
|
||||
//! This file is intended to be the first file included to any
|
||||
//! Open CASCADE source. It defines platform-specific pre-processor
|
||||
//! macros necessary for correct compilation of Open CASCADE code.
|
||||
|
||||
#ifndef _Standard_Macro_HeaderFile
|
||||
# define _Standard_Macro_HeaderFile
|
||||
|
||||
//! @def Standard_OVERRIDE
|
||||
//! Should be used in declarations of virtual methods overriden in the
|
||||
//! derived classes, to cause compilation error in the case if that virtual
|
||||
//! function disappears or changes its signature in the base class.
|
||||
//!
|
||||
//! Expands to C++11 keyword "override" on compilers that are known to
|
||||
//! suppot it; empty in other cases.
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201100L)
|
||||
// part of C++11 standard
|
||||
#define Standard_OVERRIDE override
|
||||
@@ -29,16 +37,69 @@
|
||||
#define Standard_OVERRIDE
|
||||
#endif
|
||||
|
||||
// Macro for marking variables / functions as possibly unused
|
||||
// so that compiler will not emit redundant "unused" warnings.
|
||||
//! @def Standard_FALLTHROUGH
|
||||
//! Should be used in a switch statement immediately before a case label,
|
||||
//! if code associated with the previous case label may fall through to that
|
||||
//! next label (i.e. does not end with "break" or "return" etc.).
|
||||
//! This macro indicates that the fall through is intentional and should not be
|
||||
//! diagnosed by a compiler that warns on fallthrough.
|
||||
//!
|
||||
//! Expands to C++17 attribute statement "[[fallthrough]];" on compilers that
|
||||
//! declare support of C++17, or to "__attribute__((fallthrough));" on
|
||||
//! GCC 7+.
|
||||
#if defined(__cplusplus) && (__cplusplus >= 201703L)
|
||||
// part of C++17 standard
|
||||
#define Standard_FALLTHROUGH [[fallthrough]];
|
||||
#elif defined(__GNUC__) && (__GNUC__ >= 7)
|
||||
// gcc 7+
|
||||
#define Standard_FALLTHROUGH __attribute__((fallthrough));
|
||||
#else
|
||||
#define Standard_FALLTHROUGH
|
||||
#endif
|
||||
|
||||
//! @def Standard_UNUSED
|
||||
//! Macro for marking variables / functions as possibly unused
|
||||
//! so that compiler will not emit redundant "unused" warnings.
|
||||
//!
|
||||
//! Expands to "__attribute__((unused))" on GCC and CLang.
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define Standard_UNUSED __attribute__((unused))
|
||||
#else
|
||||
#define Standard_UNUSED
|
||||
#endif
|
||||
|
||||
// Macro Standard_DEPRECATED("message") can be used to declare a method deprecated.
|
||||
// If OCCT_NO_DEPRECATED is defined, Standard_DEPRECATED is defined empty.
|
||||
//! @def Standard_THREADLOCAL
|
||||
//! Define Standard_THREADLOCAL modifier as C++11 thread_local keyword where it is available.
|
||||
#if defined(__clang__)
|
||||
// CLang version: standard CLang > 3.3 or XCode >= 8 (but excluding 32-bit ARM)
|
||||
// Note: this has to be in separate #if to avoid failure of preprocessor on other platforms
|
||||
#if __has_feature(cxx_thread_local)
|
||||
#define Standard_THREADLOCAL thread_local
|
||||
#endif
|
||||
#elif defined(__INTEL_COMPILER)
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1900 && __INTEL_COMPILER > 1400)
|
||||
// requires msvcrt vc14+ (Visual Studio 2015+)
|
||||
#define Standard_THREADLOCAL thread_local
|
||||
#elif (!defined(_MSC_VER) && __INTEL_COMPILER > 1500)
|
||||
#define Standard_THREADLOCAL thread_local
|
||||
#endif
|
||||
#elif (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
// msvcrt coming with vc14+ (VS2015+)
|
||||
#define Standard_THREADLOCAL thread_local
|
||||
#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)))
|
||||
// GCC >= 4.8
|
||||
#define Standard_THREADLOCAL thread_local
|
||||
#endif
|
||||
|
||||
#ifndef Standard_THREADLOCAL
|
||||
#define Standard_THREADLOCAL
|
||||
#endif
|
||||
|
||||
//! @def Standard_DEPRECATED("message")
|
||||
//! Can be used in declaration of a method or a class to mark it as deprecated.
|
||||
//! Use of such method or class will cause compiler warning (if supported by
|
||||
//! compiler and unless disabled).
|
||||
//! If macro OCCT_NO_DEPRECATED is defined, Standard_DEPRECATED is defined empty.
|
||||
#ifdef OCCT_NO_DEPRECATED
|
||||
#define Standard_DEPRECATED(theMsg)
|
||||
#else
|
||||
@@ -53,9 +114,14 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Disable warnings about deprecated features.
|
||||
// This is useful for sections of code kept for backward compatibility and scheduled for removal.
|
||||
|
||||
//! @def Standard_DISABLE_DEPRECATION_WARNINGS
|
||||
//! Disables warnings on use of deprecated features (see Standard_DEPRECATED),
|
||||
//! from the current point till appearance of Standard_ENABLE_DEPRECATION_WARNINGS macro.
|
||||
//! This is useful for sections of code kept for backward compatibility and scheduled for removal.
|
||||
//!
|
||||
//! @def Standard_ENABLE_DEPRECATION_WARNINGS
|
||||
//! Enables warnings on use of deprecated features previously disabled by
|
||||
//! Standard_DISABLE_DEPRECATION_WARNINGS.
|
||||
#if defined(__ICL) || defined (__INTEL_COMPILER)
|
||||
#define Standard_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:1478))
|
||||
#define Standard_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop))
|
||||
@@ -72,6 +138,13 @@
|
||||
#define Standard_ENABLE_DEPRECATION_WARNINGS
|
||||
#endif
|
||||
|
||||
//! @def OCCT_NO_RVALUE_REFERENCE
|
||||
//! Disables methods and constructors that use rvalue references
|
||||
//! (C++11 move semantics) not supported by obsolete compilers.
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||
#define OCCT_NO_RVALUE_REFERENCE
|
||||
#endif
|
||||
|
||||
# ifdef _WIN32
|
||||
|
||||
// We must be careful including windows.h: it is really poisonous stuff!
|
||||
@@ -118,7 +191,15 @@
|
||||
|
||||
#endif
|
||||
|
||||
# if defined(_WIN32) && !defined(HAVE_NO_DLL)
|
||||
//! @def Standard_EXPORT
|
||||
//! This macro should be used in declarations of public methods
|
||||
//! to ensure that they are exported from DLL on Windows and thus
|
||||
//! can be called from other (dependent) libraries or applications.
|
||||
//!
|
||||
//! If macro OCCT_STATIC_BUILD is defined, then Standard_EXPORT
|
||||
//! is set to empty.
|
||||
|
||||
# if defined(_WIN32) && !defined(OCCT_STATIC_BUILD) && !defined(HAVE_NO_DLL)
|
||||
|
||||
//======================================================
|
||||
// Windows-specific definitions
|
||||
@@ -167,21 +248,9 @@
|
||||
|
||||
# endif /* _WIN32 */
|
||||
|
||||
//======================================================
|
||||
// Other
|
||||
//======================================================
|
||||
|
||||
# ifndef __Standard_API
|
||||
# if !defined(_WIN32) || defined(__Standard_DLL) || defined(__FSD_DLL) || defined(__MMgt_DLL) || defined(__OSD_DLL) || defined(__Plugin_DLL) || defined(__Quantity_DLL) || defined(__Resource_DLL) || defined(__SortTools_DLL) || defined(__StdFail_DLL) || defined(__Storage_DLL) || defined(__TColStd_DLL) || defined(__TCollection_DLL) || defined(__TShort_DLL) || defined(__Units_DLL) || defined(__UnitsAPI_DLL) || defined(__Dico_DLL)
|
||||
# define __Standard_API Standard_EXPORT
|
||||
# define __Standard_APIEXTERN Standard_EXPORTEXTERN
|
||||
# else
|
||||
# define __Standard_API Standard_IMPORT
|
||||
# define __Standard_APIEXTERN Standard_IMPORT
|
||||
# endif // __Standard_DLL
|
||||
# endif // __Standard_API
|
||||
|
||||
// Support of Universal Windows Platform
|
||||
//! @def OCCT_UWP
|
||||
//! This macro is defined on Windows platform in the case if the code
|
||||
//! is being compiled for UWP (Universal Windows Platform).
|
||||
#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_APP
|
||||
#define OCCT_UWP
|
||||
#else
|
||||
|
Reference in New Issue
Block a user