From 0390ca3c0172ee05c68218446e948db0bcca9ef1 Mon Sep 17 00:00:00 2001 From: Hoop77 <p.badenhoop@gmx.de> Date: Sun, 21 Jan 2018 23:24:03 +0100 Subject: [PATCH] added Busyable to Timer.h --- NetworkingLib/CMakeLists.txt | 3 +- NetworkingLib/include/Busyable.h | 34 +++++------------ NetworkingLib/include/Closeable.h | 25 ++++++++++++- NetworkingLib/include/ServiceClient.h | 2 +- NetworkingLib/include/Timer.h | 21 +++++++++-- NetworkingLib/src/Busyable.cpp | 54 +++++++++++++++++++++++++++ NetworkingLib/src/Timer.cpp | 52 ++++++++++++++++---------- 7 files changed, 138 insertions(+), 53 deletions(-) create mode 100644 NetworkingLib/src/Busyable.cpp diff --git a/NetworkingLib/CMakeLists.txt b/NetworkingLib/CMakeLists.txt index 71c9cbf9..6bb23b2e 100644 --- a/NetworkingLib/CMakeLists.txt +++ b/NetworkingLib/CMakeLists.txt @@ -46,7 +46,8 @@ set(SOURCE_FILES src/Time.cpp src/Networking.cpp src/Socket.cpp - src/Stream.cpp) + src/Stream.cpp + src/Busyable.cpp) add_library(NetworkingLib STATIC ${SOURCE_FILES}) set(PUBLIC_HEADER_FILES diff --git a/NetworkingLib/include/Busyable.h b/NetworkingLib/include/Busyable.h index 043e499e..df60b123 100644 --- a/NetworkingLib/include/Busyable.h +++ b/NetworkingLib/include/Busyable.h @@ -23,8 +23,7 @@ public: * @attention Returning false does not guarantee that a subsequent * BusyLock instantiation with this object won't throw! */ - bool isBusy() const noexcept - { return busy; } + bool isBusy() const noexcept; private: std::mutex busyMutex; @@ -34,37 +33,22 @@ private: class BusyLock { public: - BusyLock(Busyable & busyable) - : busyable(busyable) - { - if (!busyable.busyMutex.try_lock()) - throw error::Busy{}; + BusyLock(Busyable & busyable); - owns = true; - busyable.busy = true; - } - - ~BusyLock() - { - unlock(); - } + ~BusyLock(); BusyLock(const BusyLock &) = delete; BusyLock & operator=(const BusyLock &) = delete; - void unlock() - { - if (owns) - { - busyable.busy = false; - busyable.busyMutex.unlock(); - owns = false; - } - } + BusyLock(BusyLock && other) noexcept; + + BusyLock & operator=(BusyLock && other) noexcept; + + void unlock(); private: - Busyable & busyable; + Busyable * busyable{nullptr}; std::atomic<bool> owns{false}; }; diff --git a/NetworkingLib/include/Closeable.h b/NetworkingLib/include/Closeable.h index b3cd704b..92e9497f 100644 --- a/NetworkingLib/include/Closeable.h +++ b/NetworkingLib/include/Closeable.h @@ -18,12 +18,32 @@ template<typename Closeable> class Closer { public: - Closer(Closeable & closeable) : closeable(closeable) + Closer(Closeable & closeable) + : closeable(closeable) {} ~Closer() { - close(closeable); + if (alive) + close(closeable); + } + + Closer(const Closer &) = delete; + + Closer & operator=(const Closer &) = delete; + + Closer(Closer && other) + : closeable(other.closeable) + { + other.alive = false; + } + + Closer & operator=(Closer && other) + { + closeable = other.closeable; + alive = other.alive; + other.alive = false; + return *this; } static void close(Closeable & closeable) @@ -34,6 +54,7 @@ public: private: Closeable & closeable; + bool alive{true}; }; template<typename Closeable> diff --git a/NetworkingLib/include/ServiceClient.h b/NetworkingLib/include/ServiceClient.h index d87bb16d..a6af95c6 100644 --- a/NetworkingLib/include/ServiceClient.h +++ b/NetworkingLib/include/ServiceClient.h @@ -182,7 +182,7 @@ private: time::Duration timeout; time::TimePoint startTime; boost::asio::streambuf buffer; - closeable::Closer <Socket> closer; + closeable::Closer<Socket> closer; }; }; diff --git a/NetworkingLib/include/Timer.h b/NetworkingLib/include/Timer.h index d1ae35b9..25eb9978 100644 --- a/NetworkingLib/include/Timer.h +++ b/NetworkingLib/include/Timer.h @@ -9,13 +9,16 @@ #include <boost/asio.hpp> #include <boost/asio/steady_timer.hpp> #include "Time.h" +#include "Busyable.h" namespace networking { namespace time { -class Timer : public std::enable_shared_from_this<Timer> +class Timer + : public std::enable_shared_from_this<Timer> + , private Busyable { private: struct PrivateTag @@ -31,17 +34,27 @@ public: static Ptr create(Networking & net); - void startTimeout(const time::Duration & duration, TimeoutHandler handler); + void startTimeout(const time::Duration & duration, const TimeoutHandler & handler); - void startPeriodicTimeout(const time::Duration & interval, TimeoutHandler handler); + void startPeriodicTimeout(const time::Duration & interval, const TimeoutHandler & handler); void stop(); private: + struct AsyncState + { + AsyncState(Ptr self, const TimeoutHandler & handler, const time::Duration & duration); + + BusyLock busyLock; + Ptr self; + TimeoutHandler handler; + time::Duration duration; + }; + boost::asio::basic_waitable_timer<time::Clock> timer; std::atomic<bool> enabled{true}; - void nextPeriod(const time::Duration & interval, TimeoutHandler handler); + void nextPeriod(std::shared_ptr<AsyncState> & state); }; } diff --git a/NetworkingLib/src/Busyable.cpp b/NetworkingLib/src/Busyable.cpp new file mode 100644 index 00000000..fc994b30 --- /dev/null +++ b/NetworkingLib/src/Busyable.cpp @@ -0,0 +1,54 @@ +// +// Created by philipp on 21.01.18. +// + +#include "../include/Busyable.h" + +namespace networking +{ + +bool Busyable::isBusy() const noexcept +{ + return busy; +} + +BusyLock::BusyLock(Busyable & busyable) : busyable(&busyable) +{ + if (!busyable.busyMutex.try_lock()) + throw error::Busy{}; + + owns = true; + busyable.busy = true; +} + +BusyLock::~BusyLock() +{ + if (owns) + unlock(); +} + +BusyLock::BusyLock(BusyLock && other) noexcept + : busyable(other.busyable) + , owns(other.owns.load()) +{ + other.busyable = nullptr; + other.owns = false; +} + +BusyLock & BusyLock::operator=(BusyLock && other) noexcept +{ + busyable = other.busyable; + owns = other.owns.load(); + + other.busyable = nullptr; + other.owns = false; +} + +void BusyLock::unlock() +{ + busyable->busy = false; + busyable->busyMutex.unlock(); + owns = false; +} + +} \ No newline at end of file diff --git a/NetworkingLib/src/Timer.cpp b/NetworkingLib/src/Timer.cpp index 8e1a10b3..5af7265f 100644 --- a/NetworkingLib/src/Timer.cpp +++ b/NetworkingLib/src/Timer.cpp @@ -19,36 +19,41 @@ Timer::Ptr Timer::create(Networking & net) return std::make_shared<Timer>(PrivateTag{}, net); } -void Timer::startTimeout(const time::Duration & duration, TimeoutHandler handler) +void Timer::startTimeout(const time::Duration & duration, const TimeoutHandler & handler) { + auto self = shared_from_this(); + auto state = std::make_shared<AsyncState>(self, handler, duration); + enabled = true; - auto self = shared_from_this(); timer.expires_from_now(duration); timer.async_wait( - [self, handler](const boost::system::error_code & error) + [state](const boost::system::error_code & error) mutable { - if (error || !self->enabled) + if (error || !state->self->enabled) return; - handler(); + state->busyLock.unlock(); + state->handler(); }); } -void Timer::startPeriodicTimeout(const time::Duration & interval, Timer::TimeoutHandler handler) +void Timer::startPeriodicTimeout(const time::Duration & interval, const TimeoutHandler & handler) { + auto self = shared_from_this(); + auto state = std::make_shared<AsyncState>(self, handler, interval); + enabled = true; - auto self = shared_from_this(); timer.expires_from_now(interval); timer.async_wait( - [self, interval, handler](const boost::system::error_code & error) + [state = std::move(state)](const boost::system::error_code & error) mutable { - if (error || !self->enabled) + if (error || !state->self->enabled) return; - handler(); - self->nextPeriod(interval, handler); + state->handler(); + state->self->nextPeriod(state); }); } @@ -62,23 +67,30 @@ void Timer::stop() timer.cancel(ignoredError); } -void Timer::nextPeriod(const time::Duration & interval, Timer::TimeoutHandler handler) +void Timer::nextPeriod(std::shared_ptr<AsyncState> & state) { - if (!enabled) + if (!state->self->enabled) return; - auto self = shared_from_this(); - timer.expires_at(timer.expires_at() + interval); - timer.async_wait( - [self, interval, handler](const boost::system::error_code & error) + state->self->timer.expires_at(state->self->timer.expires_at() + state->duration); + state->self->timer.async_wait( + [state](const boost::system::error_code & error) mutable { - if (error || !self->enabled) + if (error || !state->self->enabled) return; - handler(); - self->nextPeriod(interval, handler); + state->handler(); + state->self->nextPeriod(state); }); } +Timer::AsyncState::AsyncState(Timer::Ptr self, const Timer::TimeoutHandler & handler, const time::Duration & duration) + : busyLock(*self) + , self(self) + , handler(handler) + , duration(duration) +{ +} + } } \ No newline at end of file -- GitLab