File thread_looper.hpp¶
File List > cubrid > src > thread > thread_looper.hpp
Go to the documentation of this file
/*
* Copyright 2008 Search Solution Corporation
* Copyright 2016 CUBRID Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
* thread_looper - interface for thread looping patterns
*/
#ifndef _THREAD_LOOPER_HPP_
#define _THREAD_LOOPER_HPP_
#include "perf_def.hpp"
#include <array>
#include <atomic>
#include <chrono>
#include <functional>
#include <cassert>
#include <cinttypes>
#include <cstdint>
namespace cubthread
{
// definitions
typedef std::chrono::system_clock::duration delta_time;
typedef std::function<void (bool &, delta_time &)> period_function;
// for increasing period pattern
const std::size_t MAX_LOOPER_PERIODS = 3;
// forward def
class waiter;
// cubthread::looper
//
// description
// used for loops that require pausing.
// defines the wait pattern between each loop iteration
// should be used together with a waiter
//
// how to use
//
// // define a loop pattern and then loop and put waiter to sleep on each iteration
//
// // example using increasing wait patterns
//
// // declare period type for this example
// typedef std::chrono::duration<std::uint64, std::chrono::milliseconds milli_period_type;
// // declare increasing waiting periods
// // wait first for 1 millisecond, then for 100, then for 1000, then infinite
// std::array<milli_period_type, THREE> periods = {{ 1, 100, 1000 }};
// // create looper
// looper_shared_variable = new loop_pattern (periods);
//
// // declare waiter
// while (!looper.is_stopped ())
// {
// // do work
//
// // now sleep until timeout or wakeup
// looper.put_to_sleep (waiter);
// // thread woke up
// }
// // loop is stopped calling looper_shared_variable->stop ();
//
class looper
{
public:
// constructors
// default looping pattern; always wait until wakeup on each loop
looper ();
// copy other loop pattern
looper (const looper &other);
// loop and wait based on value provided by setup_period_function
looper (const period_function &setup_period_function);
// loop and wait for a fixed period of time
looper (const delta_time &fixed_period);
// loop and wait for increasing periods of time
//
// the sleep time is increased according to periods for each sleep that times out
// sleep timer is reset when sleep doesn't time out
template<std::size_t Count>
looper (const std::array<delta_time, Count> periods);
// dtor
~looper (void);
// put waiter to sleep according to loop pattern
void put_to_sleep (waiter &waiter_arg);
// reset looper; only useful for increasing period pattern
void reset (void);
// stop looping; no waits after this
bool stop (void);
// is looper stopped
bool is_stopped (void) const;
// return true if waiter was woken up before timeout, for more details see put_to_sleep (waiter &)
bool was_woken_up (void) const;
// statistics
static std::size_t get_stats_value_count (void);
static const char *get_stat_name (std::size_t stat_index);
void get_stats (cubperf::stat_value *stats_out);
private:
enum wait_type
{
INF_WAITS,
FIXED_WAITS,
INCREASING_WAITS,
CUSTOM_WAITS,
};
void setup_fixed_waits (bool &is_timed_wait, delta_time &period);
void setup_infinite_wait (bool &is_timed_wait, delta_time &period);
void setup_increasing_waits (bool &is_timed_wait, delta_time &period);
std::size_t m_periods_count; // the period count, used by increasing period pattern
delta_time m_periods[MAX_LOOPER_PERIODS]; // period array
std::atomic<std::size_t> m_period_index; // current period index
std::atomic<bool> m_stop; // when true, loop is stopped; no waits
std::atomic<bool> m_was_woken_up; // when true, waiter was woken up before timeout
period_function m_setup_period; // function used to refresh period on every run
// a time point that represents the start of task execution
// used by put_to_sleep function in order to sleep for difference between period interval and task execution time
std::chrono::system_clock::time_point m_start_execution_time;
// statistics
cubperf::statset &m_stats;
// my type
wait_type m_wait_type;
};
/************************************************************************/
/* Template implementation */
/************************************************************************/
template<std::size_t Count>
looper::looper (const std::array<delta_time, Count> periods)
: looper ()
{
static_assert (Count <= MAX_LOOPER_PERIODS, "Count template cannot exceed MAX_LOOPER_PERIODS=3");
m_periods_count = std::min (Count, MAX_LOOPER_PERIODS);
// wait increasing period on timeouts
for (std::size_t i = 0; i < m_periods_count; i++)
{
m_periods[i] = periods[i];
// check increasing periods
assert (i == 0 || m_periods[i - 1] < m_periods[i]);
}
m_setup_period = std::bind (&looper::setup_increasing_waits, std::ref (*this), std::placeholders::_1,
std::placeholders::_2);
m_wait_type = INCREASING_WAITS;
}
} // namespace cubthread
#endif // _THREAD_LOOPER_HPP_