mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-14 13:30:48 +03:00
0029935: Foundation Classes - introduce OSD_ThreadPool class defining a thread pool
New class OSD_ThreadPool has been introduced to define a Thread Pool for multi-threading algorithm. Thread Pool assigns a serial number for each thread allowing Multi-Threading algorithm to allocate thread-local storage variables as an array whose size is the same as the number of threads. OSD_ThreadPool also redirects exceptions to a thread calling parallel execution and consistently initializes FPE exception handling. New class Standard_Condition provides a platform-independent tool similar to Event in WinAPI. A new auxiliary function Standard_Atomic_CompareAndSwap() has been introduced for performing atomic compare and swap of integer number. Standard_Atomic_Increment/Standard_Atomic_Decrement fallback implementation using ASM code for x86 processors for GCC has been dropped; instead, it is expected that GCC should be properly configured targeting modern x86 architectures. OSD_Signal now declares fFltExceptions as thread_local variable accessible through OSD::ToCatchFloatingSignals() property. Standard_THREADLOCAL macro (wrapping thread_local attribute) has been moved to public header Standard_Macro.hxx. OSD_Parallel::ForEach() has been extended with new optional parameter theNbItems and uses OSD_ThreadPool::DefaultPool().
This commit is contained in:
@@ -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
|
||||
|
@@ -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) && ! 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,33 +58,6 @@ static void deallocate_message(Standard_CString aMessage)
|
||||
}
|
||||
}
|
||||
|
||||
//! @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
|
||||
|
||||
// ******************************************************************
|
||||
// Standard_Failure *
|
||||
// ******************************************************************
|
||||
|
@@ -68,6 +68,33 @@
|
||||
#define Standard_UNUSED
|
||||
#endif
|
||||
|
||||
//! @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
|
||||
|
Reference in New Issue
Block a user