diff --git a/simgear/threads/SGThread.cxx b/simgear/threads/SGThread.cxx index 4c618b99..0c1c5a30 100644 --- a/simgear/threads/SGThread.cxx +++ b/simgear/threads/SGThread.cxx @@ -4,6 +4,7 @@ // // Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au // Copyright (C) 2011 Mathias Froehlich +// Copyright (C) 2020 Erik Hofman // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -36,178 +37,49 @@ #include #if _WIN32 -# include # include #else # include -# include -# include -# include #endif -struct SGWaitCondition::PrivateData { - PrivateData(void) - { - } - ~PrivateData(void) - { - } - void signal(void) - { - bool waiting; - - { - std::lock_guard lock(_mtx); - waiting = !ready; - ready = true; - } - - if (waiting) { - _condition.notify_one(); - } - } - - void broadcast(void) - { - bool waiting; - - { - std::lock_guard lock(_mtx); - waiting = !ready; - ready = true; - } - - if (waiting) { - _condition.notify_all(); - } - } - - void wait(std::mutex& mutex) noexcept - { - mutex.unlock(); - - { - std::unique_lock lock(_mtx); - _condition.wait(lock, [this]{ return ready; } ); - ready = false; - } - -#ifndef NDEBUG -# if _WIN32 -// native_handle_type *m = mutex.native_handle(); -// assert(m->LockCount == 0); -# else - pthread_mutex_t *m = mutex.native_handle(); - assert(m->__data.__count == 0); -# endif -#endif - mutex.lock(); - } - - bool wait(std::mutex& mutex, unsigned msec) noexcept - { - auto timeout = std::chrono::milliseconds(msec); - - mutex.unlock(); - - { - std::unique_lock lock(_mtx); - _condition.wait_for(lock, timeout, [this]{ return ready; } ); - ready = false; - } - -#ifndef NDEBUG -# if _WIN32 -// native_handle_type *m = mutex.native_handle(); -// assert(m->LockCount == 0); -# else - pthread_mutex_t *m = mutex.native_handle(); - assert(m->__data.__count == 0); -# endif -#endif - mutex.lock(); - - return true; - } - - std::mutex _mtx; - std::condition_variable _condition; - std::atomic m_holder; - -private: - bool ready = false; -}; - -struct SGThread::PrivateData { - PrivateData() - { - } - ~PrivateData() - { - // If we are still having a started thread and nobody waited, - // now detach ... - if (!_started) - return; - _thread.detach(); - } - - static void *start_routine(void* data) - { - SGThread* thread = reinterpret_cast(data); - thread->run(); - return 0; - } - - bool start(SGThread& thread) - { - if (_started) - return false; - - try { - _thread = std::thread(start_routine, &thread); - } catch (std::runtime_error &ex) { - return false; - } - - _started = true; - return true; - } - - void join() - { - if (!_started) - return; - - _thread.join(); - _started = false; - } - - std::thread _thread; - bool _started = false; -}; - -SGThread::SGThread() : - _privateData(new PrivateData) +SGThread::SGThread() { } SGThread::~SGThread() { - delete _privateData; - _privateData = 0; + // If we are still having a started thread and nobody waited, + // now detach ... + if (!_started) + return; + _thread.detach(); } bool SGThread::start() { - return _privateData->start(*this); + if (_started) + return false; + + try { + _thread = std::thread(start_routine, this); + } catch (std::runtime_error &ex) { + return false; + } + + _started = true; + return true; } void SGThread::join() { - _privateData->join(); + if (!_started) + return; + + _thread.join(); + _started = false; } long SGThread::current( void ) @@ -219,40 +91,100 @@ long SGThread::current( void ) #endif } +void *SGThread::start_routine(void* data) +{ + SGThread* thread = reinterpret_cast(data); + thread->run(); + return 0; +} -SGWaitCondition::SGWaitCondition() : - _privateData(new PrivateData) + +SGWaitCondition::SGWaitCondition() { } SGWaitCondition::~SGWaitCondition() { - delete _privateData; - _privateData = 0; } void SGWaitCondition::wait(std::mutex& mutex) { - _privateData->wait(mutex); +#ifndef NDEBUG + try { + mutex.unlock(); + } catch(const std::system_error& e) { + SG_LOG(SG_GENERAL, SG_ALERT, "Unlocking error " << e.what() ); + } +#else + mutex.unlock(); +#endif + + { + std::unique_lock lock(_mtx); + _condition.wait(lock, [this]{ return ready; } ); + ready = false; + } + +#ifndef NDEBUG + try { + mutex.lock(); + } catch(const std::system_error& e) { + SG_LOG(SG_GENERAL, SG_ALERT, "Locking error " << e.what() ); + } +#else + mutex.lock(); +#endif } bool SGWaitCondition::wait(std::mutex& mutex, unsigned msec) { - return _privateData->wait(mutex, msec); + auto timeout = std::chrono::milliseconds(msec); + + mutex.unlock(); + + { + std::unique_lock lock(_mtx); + _condition.wait_for(lock, timeout, [this]{ return ready; } ); + ready = false; + } + + mutex.lock(); + + return true; } void SGWaitCondition::signal() { - _privateData->signal(); + bool waiting; + + { + std::lock_guard lock(_mtx); + waiting = !ready; + ready = true; + } + + if (waiting) { + _condition.notify_one(); + } } void SGWaitCondition::broadcast() { - _privateData->broadcast(); + bool waiting; + + { + std::lock_guard lock(_mtx); + waiting = !ready; + ready = true; + } + + if (waiting) { + _condition.notify_all(); + } } diff --git a/simgear/threads/SGThread.hxx b/simgear/threads/SGThread.hxx index ba9f52d2..738552e7 100644 --- a/simgear/threads/SGThread.hxx +++ b/simgear/threads/SGThread.hxx @@ -4,6 +4,7 @@ // // Copyright (C) 2001 Bernard Bright - bbright@bigpond.net.au // Copyright (C) 2011 Mathias Froehlich +// Copyright (C) 2020 Erik Hofman // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -23,6 +24,7 @@ #ifndef SGTHREAD_HXX_INCLUDED #define SGTHREAD_HXX_INCLUDED 1 +#include #include #include #include @@ -78,18 +80,20 @@ protected: */ virtual void run() = 0; + /** + * General thread starter routine. + */ + static void *start_routine(void* data); + private: // Disable copying. SGThread(const SGThread&); SGThread& operator=(const SGThread&); - struct PrivateData; - PrivateData* _privateData; - - friend struct PrivateData; + std::thread _thread; + bool _started = false; }; -class SGWaitCondition; /** * A condition variable is a synchronization device that allows threads to @@ -146,8 +150,9 @@ private: SGWaitCondition(const SGWaitCondition&); SGWaitCondition& operator=(const SGWaitCondition&); - struct PrivateData; - PrivateData* _privateData; + bool ready = false; + std::mutex _mtx; + std::condition_variable _condition; }; ///