diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 817e5a1..c1d51bb 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -34,17 +34,27 @@ INCLUDE_DIRECTORIES( ${TexC_BINARY_DIR}/IO/include ) INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/Core/include ) +SET( THREAD_API "None" ) FIND_PACKAGE( Boost COMPONENTS thread system ) IF( Boost_FOUND ) INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIR} ) + SET( THREAD_API "Boost" ) + SET( SOURCES ${SOURCES} "src/ThreadBoost.cpp" ) + + LINK_DIRECTORIES( ${Boost_LIBRARY_DIR} ) +ENDIF() + +IF( NOT THREAD_API MATCHES "None") + SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp" ) SET( SOURCES ${SOURCES} "src/WorkerQueue.cpp" ) + SET( HEADERS ${HEADERS} "src/Thread.h" ) SET( HEADERS ${HEADERS} "src/ThreadGroup.h" ) SET( HEADERS ${HEADERS} "src/WorkerQueue.h" ) - - LINK_DIRECTORIES( ${Boost_LIBRARY_DIR} ) +ELSE() + MESSAGE( FATAL_ERROR "Could not find suitable threading library." ) ENDIF() ADD_LIBRARY( TexCompCore diff --git a/Core/src/Thread.h b/Core/src/Thread.h new file mode 100644 index 0000000..79cdfb4 --- /dev/null +++ b/Core/src/Thread.h @@ -0,0 +1,79 @@ +#ifndef __TEX_COMP_THREAD_H__ +#define __TEX_COMP_THREAD_H__ + +#include "TexCompTypes.h" + +//////////////////////////////////////////////////////////////////////////////// +// +// Base implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCThreadBaseImpl; +class TCThreadBaseImplFactory; +class TCThreadBase { + protected: + TCThreadBase(const TCThreadBaseImplFactory &); + TCThreadBase(const TCThreadBase &); + TCThreadBase &operator=(const TCThreadBase &); + ~TCThreadBase(); + + TCThreadBaseImpl *m_Impl; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCThread : public TCThreadBase { + + public: + template + TCThread(C &); + ~TCThread(); + + void Join(); + +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Mutex implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCMutex : public TCThreadBase { + friend class TCLockImpl; + public: + TCMutex(); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Lock implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCLock : public TCThreadBase { + friend class TCConditionVariableImpl; + public: + TCLock(TCMutex &); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Condition Variable implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCConditionVariable : public TCThreadBase { + public: + TCConditionVariable(); + void Wait(TCLock &); + void NotifyOne(); + void NotifyAll(); +}; + +#endif //__TEX_COMP_THREAD_H__ diff --git a/Core/src/ThreadBoost.cpp b/Core/src/ThreadBoost.cpp new file mode 100644 index 0000000..84cff2b --- /dev/null +++ b/Core/src/ThreadBoost.cpp @@ -0,0 +1,213 @@ +#include "Thread.h" + +#include + +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +// +// Base Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCThreadBaseImpl { + int m_ReferenceCount; +public: + TCThreadBaseImpl() + : m_ReferenceCount(1) + { } + + void IncreaseReferenceCount() { m_ReferenceCount++; } + void DecreaseReferenceCount() { m_ReferenceCount--; } + + int GetReferenceCount() const { return m_ReferenceCount; } +}; + +class TCThreadBaseImplFactory { +public: + TCThreadBaseImplFactory() { } + virtual ~TCThreadBaseImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const = 0; +}; + +TCThreadBase::TCThreadBase(const TCThreadBaseImplFactory &factory) + : m_Impl(factory.CreateImpl()) +{ } + +TCThreadBase::TCThreadBase(const TCThreadBase &other) + : m_Impl(other.m_Impl) +{ + assert(m_Impl->GetReferenceCount() > 0); + m_Impl->IncreaseReferenceCount(); +} + +TCThreadBase &TCThreadBase::operator=(const TCThreadBase &other) { + assert(m_Impl->GetReferenceCount() > 0); + m_Impl->DecreaseReferenceCount(); + m_Impl = other.m_Impl; + m_Impl->IncreaseReferenceCount(); +} + +TCThreadBase::~TCThreadBase() { + if(m_Impl->GetReferenceCount() <= 1) { + delete m_Impl; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCThreadImpl : public TCThreadBaseImpl { + boost::thread m_Thread; +public: + template + TCThreadImpl(C &callable) + : m_Thread(callable) + { } + + void Join() { + m_Thread.join(); + } +}; + +template +class TCThreadImplFactory : public TCThreadBaseImplFactory { + C &m_Callable; +public: + TCThreadImplFactory(C &callable) : m_Callable(callable) { } + virtual ~TCThreadImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCThreadImpl(m_Callable); + } +}; + +template +TCThread::TCThread(C &callable) + : TCThreadBase(TCThreadImplFactory(callable)) +{ } + +void TCThread::Join() { + assert(m_Impl->GetReferenceCount() > 0); + ((TCThreadImpl *)m_Impl)->Join(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Mutex Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCMutexImpl : public TCThreadBaseImpl { +private: + boost::mutex m_Mutex; + +public: + boost::mutex &GetMutex() { return m_Mutex; } +}; + +class TCMutexImplFactory : public TCThreadBaseImplFactory { +public: + TCMutexImplFactory() { } + virtual ~TCMutexImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCMutexImpl(); + } +}; + +TCMutex::TCMutex() : TCThreadBase(TCMutexImplFactory()) +{ } + +//////////////////////////////////////////////////////////////////////////////// +// +// Lock Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCLockImpl : public TCThreadBaseImpl { +private: + boost::unique_lock lock; +public: + TCLockImpl(TCMutex &mutex) + : lock(((TCMutexImpl *)(mutex.m_Impl))->GetMutex()) + { } + + boost::unique_lock &GetLock() { return lock; } +}; + +class TCLockImplFactory : public TCThreadBaseImplFactory { +private: + TCMutex &m_Mutex; +public: + TCLockImplFactory(TCMutex &mutex) : m_Mutex(mutex){ } + virtual ~TCLockImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCLockImpl(m_Mutex); + } +}; + +TCLock::TCLock(TCMutex &mutex) : TCThreadBase(TCLockImplFactory(mutex)) +{ } + +//////////////////////////////////////////////////////////////////////////////// +// +// Condition Variable Implementation +// +//////////////////////////////////////////////////////////////////////////////// + +class TCConditionVariableImpl : public TCThreadBaseImpl { +private: + boost::condition_variable m_CV; +public: + TCConditionVariableImpl() { } + void Wait(TCLock &lock) { + TCLockImpl *lockImpl = (TCLockImpl *)(lock.m_Impl); + m_CV.wait(lockImpl->GetLock()); + } + + void NotifyOne() { + m_CV.notify_one(); + } + + void NotifyAll() { + m_CV.notify_all(); + } +}; + +class TCConditionVariableImplFactory : public TCThreadBaseImplFactory { +public: + TCConditionVariableImplFactory() { } + virtual ~TCConditionVariableImplFactory() { } + virtual TCThreadBaseImpl *CreateImpl() const { + return new TCConditionVariableImpl(); + } +}; + +TCConditionVariable::TCConditionVariable() + : TCThreadBase(TCConditionVariableImplFactory()) +{ } + +void TCConditionVariable::Wait(TCLock &lock) { + assert(m_Impl->GetReferenceCount() > 0); + + TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl; + impl->Wait(lock); +} + +void TCConditionVariable::NotifyOne() { + assert(m_Impl->GetReferenceCount() > 0); + + TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl; + impl->NotifyOne(); +} + +void TCConditionVariable::NotifyAll() { + assert(m_Impl->GetReferenceCount() > 0); + + TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl; + impl->NotifyAll(); +}