//================================================================================================== // S t a n d a r d Interface // T h r e a d // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // the GNU Library General Public License for more details (http://www.gnu.org).
/*DESCRIPTION*/ /* This module provides facilities to manipulate threads. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "standard/thread.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guStandardThread #define guStandardThread
// Headers //--------------------------------------------------------------------------------------- #include <cstdlib> /*INCLUDE*/ #include <vector> /*INCLUDE*/ #include <bpp/standard/keyword.hpp> /*INCLUDE*/
#ifndef USE_FORK_FOR_THREAD #ifdef SUSPEND_HEADER #include SUSPEND_HEADER /*INCLUDE*/ #endif
#ifdef THREAD_HEADER #include THREAD_HEADER /*INCLUDE*/ #endif
#ifdef THREAD_ALLOCATOR_HEADER #include THREAD_ALLOCATOR_HEADER /*INCLUDE*/ #endif #else #undef CREATE_THREAD #undef EXIT_THREAD #undef SUSPEND_THREAD #undef THREAD_TYPE #undef MUTEX_TYPE #undef CREATE_MUTEX #undef DESTROY_MUTEX #undef LOCK_MUTEX #undef RELEASE_MUTEX #undef TRY_LOCK_MUTEX #endif
// Portability //----------------------------------------------------------------------------------- #ifndef CREATE_THREAD #include <unistd.h> /*INCLUDE*/
#define CREATE_THREAD(prThread,prFunction,prData) \ switch (fork()) { \ case -1: \ (prThread)=0; \ break; \ case 0: \ (prThread)=getpid(); ((void * (*)(void *))(prFunction))((void *)(prData)); \ EXIT_THREAD; \ break; \ default: (prThread)=getpid(); \ } \
#define EXIT_THREAD (_exit(EXIT_SUCCESS)) #define SUSPEND_THREAD(prDuration) (sleep(prDuration)) #define THREAD_TYPE pid_t #define MUTEX_TYPE void * #endif
namespace bpp {
// Importation/Exportation //----------------------------------------------------------------------- #ifdef STANDARD_DLL #define dll_export DLL_EXPORT #else #define dll_export DLL_IMPORT #endif
// Namespaces //------------------------------------------------------------------------------------ #define public_area standardThread #define private_area standardThread_private
namespace public_area { /*NAMESPACE*/ using namespace standardKeyword; } namespace private_area { using namespace public_area; }
// Initialization //--------------------------------------------------------------------------------
// Macrocommands //---------------------------------------------------------------------------------
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------------Classes class clMutex; class clInitializerMutex; //-----------------------------------------------------------------------------------Variable Types /*TYPE*/ /* Thread. */ typedef THREAD_TYPE tyThread; //-----------------------------------------------------------------------------------Constant Types typedef const clMutex ctMutex; typedef const clInitializerMutex ctInitializerMutex; typedef const tyThread tcThread; }
namespace private_area { typedef BOOLEAN_TYPE tyBoolean; typedef CARDINAL_TYPE tyCardinal; typedef MUTEX_TYPE tyMutex; typedef void * tyPointer; typedef void (*tyFunction)(void);
typedef void (*tySendErrorFunction)(void); }
// Functions Interface //--------------------------------------------------------------------------- namespace public_area { function void createThread(private_area::tyFunction,private_area::tyPointer); inline void exitThread(void); inline void suspendThread(private_area::tyCardinal); }
namespace private_area { testing_mode ( function void test(void); ) }
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
commentary ( /*ERROR*/ extern_error erCreateThread; /* Can not create a new thread. */ /*ERROR*/ extern_error erMutexNotAvailable; /* The mutex facility is not available. */ /*ERROR*/ extern_error erMutexUnlocked; /* The mutex is unlocked. */ )
// Constants & Variables //------------------------------------------------------------------------- extern_dynamic_constant(private,clMutex,goDisplayMutex,?); extern_dynamic_constant(private,clMutex,goMallocMutex,?);
namespace private_area { extern function tySendErrorFunction sendCreateThreadError; extern function tySendErrorFunction sendMutexNotAvailableError; extern function tySendErrorFunction sendMutexUnlockedError; }
// M u t e x Interface //-------------------------------------------------------------------------- namespace public_area { /*CLASS clMutex */ /* Represents a mutex (mutual exclusion for threads). It is used to lock the use of a resource from other threads. */ class clMutex { //-----------------------------------------------------------------------------------------Private private_property private_area::tyBoolean atLocked; private_property private_area::tyMutex atMutex;
private_property constructor clMutex(ctMutex &); private_property clMutex & operator = (ctMutex &); //------------------------------------------------------------------------------------------Public public_property constructor clMutex(void); public_property virtual destructor clMutex(void);
public_property void lock(void); public_property void release(void); public_property private_area::tyBoolean tryLock(void); }; }
// I n i t i a l i z e r M u t e x Interface //---------------------------------------------------- namespace public_area { /*CLASS clInitializerMutex */ /* Represents a mutex that protects the initialization of a variable. */ class clInitializerMutex : public clMutex { //-----------------------------------------------------------------------------------------Private private_property private_area::tyBoolean atInitialized;
private_property constructor clInitializerMutex(ctInitializerMutex &); private_property clInitializerMutex & operator = (ctInitializerMutex &);
private_property void lock(void); //------------------------------------------------------------------------------------------Public public_property constructor clInitializerMutex(void); public_property virtual destructor clInitializerMutex(void);
public_property void release(void); public_property private_area::tyBoolean tryLock(void); }; }
// Functions Inline //------------------------------------------------------------------------------ namespace public_area { //---------------------------------------------------------------------------------------ExitThread /*FUNCTION*/ /* Exits the current thread. */ inline void exitThread(void) { EXIT_THREAD; } //------------------------------------------------------------------------------------SuspendThread /*FUNCTION*/ /* Suspends the current thread for a given number of seconds. */ inline void suspendThread(private_area::tyCardinal agDuration) { SUSPEND_THREAD(agDuration); } }
namespace private_area {}
// M u t e x Inline //----------------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clMutex */ /* Builds a mutex. */ inline clMutex::clMutex(void) : atLocked(false),atMutex() { #if defined(THREAD_SAFETY) and defined(CREATE_MUTEX) CREATE_MUTEX(atMutex); #endif } //------------------------------------------------------------------------------------------Release /*METHOD clMutex */ /* Releases the mutex. */ inline void clMutex::release(void) { #if defined(THREAD_SAFETY) and defined(RELEASE_MUTEX) if (not atLocked) { if (private_area::sendMutexUnlockedError!=nil) private_area::sendMutexUnlockedError(); } else { atLocked=false; RELEASE_MUTEX(atMutex); } #else if (private_area::sendMutexNotAvailableError!=nil) private_area::sendMutexNotAvailableError(); #endif } //---------------------------------------------------------------------------------------------Lock /*METHOD clMutex */ /* Locks the mutex. If it is already locked, the thread waits for its release to lock it again. */ inline void clMutex::lock(void) { #if defined(THREAD_SAFETY) and defined(LOCK_MUTEX) LOCK_MUTEX(atMutex); atLocked=true; #else if (private_area::sendMutexNotAvailableError!=nil) private_area::sendMutexNotAvailableError(); #endif } //------------------------------------------------------------------------------------------TryLock /*METHOD clMutex */ /* Attempts to lock the mutex. If it is already locked, the thread does not wait for its release and goes on. */ inline private_area::tyBoolean clMutex::tryLock(void) { #if defined(THREAD_SAFETY) and defined(TRY_LOCK_MUTEX) if (TRY_LOCK_MUTEX(atMutex)) { atLocked=true; return (true); } else return (false); #else if (private_area::sendMutexNotAvailableError!=nil) private_area::sendMutexNotAvailableError(); return (false); #endif } }
// I n i t i a l i z e r M u t e x Inline //------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clInitializerMutex */ /* Builds a mutex. */ inline clInitializerMutex::clInitializerMutex(void) : clMutex(),atInitialized(false) {} //---------------------------------------------------------------------------------------Destructor /*METHOD clInitializerMutex */ /* Destructs the mutex. */ inline clInitializerMutex::~clInitializerMutex(void) {} //------------------------------------------------------------------------------------------Release /*METHOD clInitializerMutex */ /* Releases the mutex. */ inline void clInitializerMutex::release(void) { atInitialized=true; safe_yes ( clMutex::release(); ) } //------------------------------------------------------------------------------------------TryLock /*METHOD clInitializerMutex */ /* Attempts to lock the mutex. If it is successful, that means the variable protected by the mutex needs to be initialized. */ inline private_area::tyBoolean clInitializerMutex::tryLock(void) { safe_yes ( if (not atInitialized) { clMutex::lock();
if (atInitialized) { clMutex::release(); return (false); }
return (true); }
return (false); )
safe_no ( return (not atInitialized); ) } }
// Namespace End //--------------------------------------------------------------------------------- } #if defined(THREAD_SAFETY) and defined(NEED_SAFE_STL_ALLOCATOR)
// T h r e a d S a f e A l l o c a t o r Interface //---------------------------------------------- template <class prType> class thread_safe_allocator { //--------------------------------------------------------------------------------------------Types private_property typedef std_allocator<prType> tyAllocator;
public_property typedef typename tyAllocator::difference_type difference_type; public_property typedef typename tyAllocator::pointer pointer; public_property typedef typename tyAllocator::reference reference; public_property typedef typename tyAllocator::size_type size_type; public_property typedef typename tyAllocator::value_type value_type;
public_property typedef typename tyAllocator::const_pointer const_pointer; public_property typedef typename tyAllocator::const_reference const_reference;
public: template <class prType2> struct rebind { public_property typedef thread_safe_allocator<prType2> other; }; //------------------------------------------------------------------------------------------Private private_property tyAllocator * atAllocator; //-------------------------------------------------------------------------------------------Public public_property thread_safe_allocator(void); public_property thread_safe_allocator(const thread_safe_allocator<prType> &); public_property ~thread_safe_allocator(void);
public: template <class prType2> thread_safe_allocator(const thread_safe_allocator<prType2> &);
public_property pointer address(reference) const; public_property const_pointer address(const_reference) const;
public_property pointer allocate(size_type,const void * = 0); public_property void construct(pointer,const_reference); public_property void deallocate(pointer,size_type); public_property void destroy(pointer); public_property size_type max_size(void) const; };
// T h r e a d S a f e A l l o c a t o r Inline //------------------------------------------------- //---------------------------------------------------------------------------------------Constructor template <class prType> inline thread_safe_allocator<prType>::thread_safe_allocator(void) { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); atAllocator=reinterpret_cast<tyAllocator *>(malloc(sizeof(tyAllocator))); new (atAllocator) tyAllocator; if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //---------------------------------------------------------------------------------------Constructor template <class prType> inline thread_safe_allocator<prType>:: thread_safe_allocator(const thread_safe_allocator<prType> & agAllocator) { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); atAllocator=reinterpret_cast<tyAllocator *>(malloc(sizeof(tyAllocator))); new (atAllocator) tyAllocator; if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //---------------------------------------------------------------------------------------Constructor template <class prType> template <class prType2> inline thread_safe_allocator<prType>:: thread_safe_allocator(const thread_safe_allocator<prType2> & agAllocator) { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); atAllocator=reinterpret_cast<tyAllocator *>(malloc(sizeof(tyAllocator))); new (atAllocator) tyAllocator; if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //----------------------------------------------------------------------------------------Destructor template <class prType> inline thread_safe_allocator<prType>::~thread_safe_allocator(void) { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); atAllocator->~allocator<prType>(); free(atAllocator); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //-------------------------------------------------------------------------------------------Address template <class prType> inline thread_safe_allocator<prType>::pointer thread_safe_allocator<prType>::address(reference agReference) const { return (atAllocator->address(agReference)); } //-------------------------------------------------------------------------------------------Address template <class prType> inline thread_safe_allocator<prType>::const_pointer thread_safe_allocator<prType>::address(const_reference agReference) const { return (atAllocator->address(agReference)); } //------------------------------------------------------------------------------------------Allocate template <class prType> inline thread_safe_allocator<prType>::pointer thread_safe_allocator<prType>::allocate(size_type agSize,const void * agPointer) { pointer lcPointer;
if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); lcPointer=atAllocator->allocate(agSize,agPointer); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); return (lcPointer); } //-----------------------------------------------------------------------------------------Construct template <class prType> inline void thread_safe_allocator<prType>:: construct(pointer agPointer,const_reference agReference) { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); atAllocator->construct(agPointer,agReference); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //----------------------------------------------------------------------------------------Deallocate template <class prType> inline void thread_safe_allocator<prType>:: deallocate(pointer agPointer,size_type agSize) { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); atAllocator->deallocate(agPointer,agSize); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //-------------------------------------------------------------------------------------------Destroy template <class prType> inline void thread_safe_allocator<prType>::destroy(pointer agPointer) { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); atAllocator->destroy(agPointer); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //------------------------------------------------------------------------------------------Max_size template <class prType> inline thread_safe_allocator<prType>::size_type thread_safe_allocator<prType>::max_size(void) const { return (atAllocator->max_size()); }
// Functions Inline //------------------------------------------------------------------------------ //---------------------------------------------------------------------------------------Operator == template <class prType1,class prType2> inline bool operator == (const thread_safe_allocator<prType1> & agAllocator1, const thread_safe_allocator<prType2> & agAllocator2) { return (*(agAllocator1.atAllocator)==*(agAllocator2.atAllocator)); } //---------------------------------------------------------------------------------------Operator != template <class prType1,class prType2> inline bool operator != (const thread_safe_allocator<prType1> & agAllocator1, const thread_safe_allocator<prType2> & agAllocator2) { return (*(agAllocator1.atAllocator)!=*(agAllocator2.atAllocator)); }
// End //------------------------------------------------------------------------------------------ #endif #undef dll_export #undef public_area #undef private_area #endif |
//================================================================================================== // S t a n d a r d Implementation // T h r e a d // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See // the GNU Library General Public License for more details (http://www.gnu.org).
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "standard/thread.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define STANDARD_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/standard/thread.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area standardThread #define private_area standardThread_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
// Initialization //--------------------------------------------------------------------------------
// Errors //---------------------------------------------------------------------------------------- namespace public_area {}
// Constants & Variables //------------------------------------------------------------------------- dynamic_constant(clMutex,goDisplayMutex); dynamic_constant(clMutex,goMallocMutex);
namespace private_area { function tySendErrorFunction sendCreateThreadError = nil; function tySendErrorFunction sendMutexNotAvailableError = nil; function tySendErrorFunction sendMutexUnlockedError = nil; }
// Static Members //-------------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Functions Implementation //---------------------------------------------------------------------- namespace public_area { //-------------------------------------------------------------------------------------CreateThread /*FUNCTION*/ /* Creates a new thread and executes a given function in it. The second parameter is a pointer to the data given to the function. */ function void createThread(private_area::tyFunction agFunction,private_area::tyPointer agData) { tyThread lcThread;
CREATE_THREAD(lcThread,agFunction,agData);
if (lcThread==0 and private_area::sendCreateThreadError!=nil) private_area::sendCreateThreadError(); } }
namespace private_area {}
// M u t e x Implementation //--------------------------------------------------------------------- namespace public_area { //---------------------------------------------------------------------------------------Destructor /*METHOD clMutex */ /* Destructs the mutex. */ property clMutex::~clMutex(void) { #if defined(THREAD_SAFETY) and defined(DESTROY_MUTEX) if (atLocked) release(); DESTROY_MUTEX(atMutex); #endif } }
// Namespace End //--------------------------------------------------------------------------------- }
// N e w & D e l e t e Implementation //--------------------------------------------------------- #if defined(THREAD_SAFETY) and defined(NEED_SAFE_PLAIN_NEW) //---------------------------------------------------------------------------------Single Plain New void * operator new(std::size_t agSize) throw(std::bad_alloc) { void * lcPointer;
if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); lcPointer=malloc(agSize); if (lcPointer==nil) throw std::bad_alloc(); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); return (lcPointer); } //-------------------------------------------------------------------------------Multiple Plain New void * operator new[](std::size_t agSize) throw(std::bad_alloc) { void * lcPointer;
if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); lcPointer=malloc(agSize); if (lcPointer==nil) throw std::bad_alloc(); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); return (lcPointer); } //------------------------------------------------------------------------------Single Plain Delete void operator delete(void * agPointer) throw() { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); free(agPointer); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //----------------------------------------------------------------------------Multiple Plain Delete void operator delete[](void * agPointer) throw() { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); free(agPointer); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } #endif
#if defined(THREAD_SAFETY) and defined(NEED_SAFE_NOTHROW_NEW) //-------------------------------------------------------------------------------Single Nothrow New void * operator new(std::size_t agSize,const std::nothrow_t &) throw() { void * lcPointer;
if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); lcPointer=malloc(agSize); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); return (lcPointer); } //-----------------------------------------------------------------------------Multiple Nothrow New void * operator new[](std::size_t agSize,const std::nothrow_t &) throw() { void * lcPointer;
if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); lcPointer=malloc(agSize); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); return (lcPointer); } //----------------------------------------------------------------------------Single Nothrow Delete void operator delete(void * agPointer,const std::nothrow_t &) throw() { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); free(agPointer); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } //--------------------------------------------------------------------------Multiple Nothrow Delete void operator delete[](void * agPointer,const std::nothrow_t &) throw() { if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->lock(); free(agPointer); if (bpp::private_area::goMallocMutex!=nil) bpp::private_area::goMallocMutex->release(); } #endif
// End //------------------------------------------------------------------------------------------- |
|