diff --git a/include/aniray/PeriodicThread.hpp b/include/aniray/PeriodicThread.hpp index 54c776f..2f5c85c 100644 --- a/include/aniray/PeriodicThread.hpp +++ b/include/aniray/PeriodicThread.hpp @@ -27,6 +27,7 @@ #ifndef ANIRAY_PERIODICTHREAD_HPP #define ANIRAY_PERIODICTHREAD_HPP +#include #include #include #include @@ -60,7 +61,7 @@ class PeriodicThread { // NOLINT(cppcoreguidelines-special-member-functions,hicp virtual void periodicAction() = 0; private: bool mWasRunning = false; - bool mRunning = false; + std::atomic_bool mRunning = false; std::chrono::milliseconds mUpdateRateMs; boost::asio::io_context mIOContext; std::unique_ptr mTimer; diff --git a/src/PeriodicThread.cpp b/src/PeriodicThread.cpp index b7834b0..2b4476a 100644 --- a/src/PeriodicThread.cpp +++ b/src/PeriodicThread.cpp @@ -24,16 +24,20 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include #include #include #include +#include #include #include #include #include // IWYU pragma: keep #include // IWYU pragma: keep +#include +#include // IWYU pragma: no_include // IWYU pragma: no_include // IWYU pragma: no_forward_declare boost::system::error_code @@ -53,16 +57,22 @@ PeriodicThread::PeriodicThread(std::chrono::milliseconds updateRateMs) void PeriodicThread::start() { if (mWasRunning) { + stop(); mIOContext.restart(); - } else { - mIOThread = std::make_unique([ObjectPtr = &mIOContext] { ObjectPtr->run(); }); } + mIOThread = std::make_unique([ObjectPtr = &mIOContext] { ObjectPtr->run(); }); mWasRunning = true; mRunning = true; } void PeriodicThread::stop() { mIOContext.stop(); + if (mIOThread) { + mIOThread->interrupt(); + if (mIOThread->joinable()) { + mIOThread->join(); + } + } mRunning = false; } @@ -81,19 +91,33 @@ void PeriodicThread::updateRate(std::chrono::milliseconds updateRateMs) { } PeriodicThread::~PeriodicThread() { - const std::unique_lock lock(mHandlerMutex); - stop(); - // if (mIOThread->joinable()) { - // mIOThread->join(); - // } + const std::unique_lock lock(mHandlerMutex); + try { + stop(); + } catch (const boost::thread_interrupted&) { + // Suppress for destructor + return; + } catch (const std::system_error& e) { + // Suppress for destructor + return; + } catch (...) { + // Suppress for destructor + return; + } + // See https://wiki.sei.cmu.edu/confluence/display/cplusplus/DCL57-CPP.+Do+not+let+exceptions+escape+from+destructors+or+deallocation+functions + // for returning in catch() } void PeriodicThread::timerHandler () { - const std::shared_lock lockHandler(mHandlerMutex); - periodicAction(); - const std::shared_lock lockUpdateRate(mUpdateRateMutex); - mTimer->expires_at(mTimer->expiry() + mUpdateRateMs); - mTimer->async_wait([this] (const boost::system::error_code&) { timerHandler(); }); + boost::this_thread::interruption_point(); + { + const std::shared_lock lockHandler(mHandlerMutex); + periodicAction(); + const std::shared_lock lockUpdateRate(mUpdateRateMutex); + mTimer->expires_at(mTimer->expiry() + mUpdateRateMs); + mTimer->async_wait([this] (const boost::system::error_code&) { timerHandler(); }); + } + boost::this_thread::interruption_point(); } } // namespace aniray