diff options
author | Sven Gothel <[email protected]> | 2022-04-10 19:19:27 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2022-04-10 19:19:27 +0200 |
commit | a41475e3bfc1e04883411d68a6a28729a1e6dff8 (patch) | |
tree | 8a3e553bdf6bfabf23fcb996c291723ce7e31e07 /include/jau | |
parent | e0a140e193224177d345fa77926592f0b71a3aea (diff) |
Add SimpleTimer class: A simple timer for timeout and interval applications, using one dedicated service_runner thread per instance.
Diffstat (limited to 'include/jau')
-rw-r--r-- | include/jau/simple_timer.hpp | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/include/jau/simple_timer.hpp b/include/jau/simple_timer.hpp new file mode 100644 index 0000000..dfa4024 --- /dev/null +++ b/include/jau/simple_timer.hpp @@ -0,0 +1,147 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2022 Gothel Software e.K. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef JAU_SIMPLE_TIMER_HPP_ +#define JAU_SIMPLE_TIMER_HPP_ + +#include <cstdint> +#include <mutex> +#include <condition_variable> +#include <thread> + +#include <jau/ordered_atomic.hpp> +#include <jau/function_def.hpp> +#include <jau/service_runner.hpp> + +namespace jau { + + /** + * A simple timer for timeout and interval applications, + * using one dedicated service_runner thread per instance. + * + * Discussion: It is contemplated to add an implementation using a unique singleton service_runner + * for multiple timer instances via event loops. + */ + class SimpleTimer { + public: + typedef SimpleTimer& Timer0_ref; + + /** + * User defined timer function using millisecond granularity. + * + * Function gets invoked for each timer event, + * i.e. after reaching the duration in milliseconds set earlier. + * + * @return duration in milliseconds for the next timer event or zero to end the timer thread. + */ + typedef FunctionDef<nsize_t, Timer0_ref> Timer_func_ms; + + private: + service_runner timer_service; + std::mutex mtx_timerfunc; + Timer_func_ms timer_func_ms; + jau::relaxed_atomic_nsize_t duration_ms; + + void timer_worker(service_runner& sr_ref) { + do { + std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms)); + Timer_func_ms tf; + { + std::unique_lock<std::mutex> lockReader(mtx_timerfunc); // RAII-style acquire and relinquish via destructor + tf = timer_func_ms; + } + if( FunctionType::Null != tf.getType() && !sr_ref.get_shall_stop() ) { + duration_ms = tf.invoke(*this); + } else { + duration_ms = 0; + } + } while ( 0 < duration_ms ); + } + + public: + SimpleTimer(const std::string& name, const nsize_t service_shutdown_timeout_ms) noexcept + : timer_service(name, service_shutdown_timeout_ms, jau::bindMemberFunc(this, &SimpleTimer::timer_worker)), + timer_func_ms(), duration_ms(0) + {} + + /** + * No copy constructor nor move constructor. + * @param o + */ + SimpleTimer(const SimpleTimer& o) = delete; + + /** + * Returns true if timer is running + */ + bool is_running() const { return timer_service.is_running(); } + + /** + * Start the timer with given user Timer_func_ms function and initial duration in milliseconds. + * + * @param duration_ms_ initial timer duration until next timer event in milliseconds + * @param tofunc user Timer_func_ms to be called on next timer event + * @return true if timer has been started, otherwise false implies timer is already running. + */ + bool start(nsize_t duration_ms_, Timer_func_ms tofunc) { + if( timer_service.is_running() ) { + return false; + } + timer_func_ms = tofunc; + duration_ms = duration_ms_; + timer_service.start(); + return true; + } + + /** + * Start or update the timer with given user Timer_func_ms function and initial duration in milliseconds. + * + * This is faster than calling stop() and start(), however, + * an already started timer user Timer_func_ms will proceed. + * + * @param duration_ms_ initial timer duration until next timer event in milliseconds + * @param tofunc user Timer_func_ms to be called on next timer event + */ + void start_or_update(nsize_t duration_ms_, Timer_func_ms tofunc) { + if( timer_service.is_running() ) { + std::unique_lock<std::mutex> lockReader(mtx_timerfunc); // RAII-style acquire and relinquish via destructor + timer_func_ms = tofunc; + duration_ms = duration_ms_; + } else { + timer_func_ms = tofunc; + duration_ms = duration_ms_; + timer_service.start(); + } + } + + /** + * Stop timer + */ + void stop() { + timer_service.stop(); + } + }; + +} /* namespace jau */ + +#endif /* JAU_SIMPLE_TIMER_HPP_ */ |