mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-16 10:08:36 +03:00
Implementation of methods OSD_Parallel::For() and ForEach() is moved to CXX files to avoid direct dependency of client code that uses OSD_Parallel on TBB headers, and necessity to link with TBB explicitly. Runtime polymorphism (virtual methods) is used to hide implementation (TBB or threads-based).
331 lines
11 KiB
C++
331 lines
11 KiB
C++
// 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.
|
|
|
|
#ifndef OSD_Parallel_HeaderFile
|
|
#define OSD_Parallel_HeaderFile
|
|
|
|
#include <Standard_Type.hxx>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
|
|
//! @brief Simple tool for code parallelization.
|
|
//!
|
|
//! 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
|
|
//! {
|
|
//! public:
|
|
//! void operator() ([proccesing instance]) const
|
|
//! {
|
|
//! //...
|
|
//! }
|
|
//! };
|
|
//! @endcode
|
|
//!
|
|
//! 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
|
|
{
|
|
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:
|
|
virtual ~IteratorInterface() {}
|
|
|
|
//! Returns true if iterators wrapped by this and theOther are equal
|
|
virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
|
|
|
|
//! Increments wrapped iterator
|
|
virtual void Increment () = 0;
|
|
|
|
//! Returns new instance of the wrapper containing copy
|
|
//! of the wrapped iterator.
|
|
virtual IteratorInterface* Clone() const = 0;
|
|
};
|
|
|
|
//! 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:
|
|
IteratorWrapper() {}
|
|
IteratorWrapper(const Type& theValue) : myValue(theValue) {}
|
|
|
|
virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
|
|
{
|
|
return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
|
|
}
|
|
|
|
virtual void Increment () Standard_OVERRIDE
|
|
{
|
|
++myValue;
|
|
}
|
|
|
|
virtual IteratorInterface* Clone() const Standard_OVERRIDE
|
|
{
|
|
return new IteratorWrapper<Type>(myValue);
|
|
}
|
|
|
|
const Type& Value() const { return myValue; }
|
|
|
|
private:
|
|
Type myValue;
|
|
};
|
|
|
|
protected:
|
|
// Note: UniversalIterator and FunctorInterface are made protected to be
|
|
// accessible from specialization using threads (non-TBB).
|
|
|
|
//! 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 the specified iterator position
|
|
Standard_EXPORT static void forEach (UniversalIterator& theBegin,
|
|
UniversalIterator& theEnd,
|
|
const FunctorInterface& theFunctor);
|
|
|
|
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 (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(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)
|
|
{
|
|
if (isForceSingleThreadExecution)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
//! 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)
|
|
{
|
|
if (isForceSingleThreadExecution)
|
|
{
|
|
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);
|
|
}
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|