1 // 2 // time_t_timer.cpp 3 // ~~~~~~~~~~~~~~~~ 4 // 5 // Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6 // 7 // Distributed under the Boost Software License, Version 1.0. (See accompanying 8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9 // 10 11 #include <boost/asio.hpp> 12 #include <ctime> 13 #include <chrono> 14 #include <iostream> 15 16 // A custom implementation of the Clock concept from the standard C++ library. 17 struct time_t_clock 18 { 19 // The duration type. 20 typedef std::chrono::steady_clock::duration duration; 21 22 // The duration's underlying arithmetic representation. 23 typedef duration::rep rep; 24 25 // The ratio representing the duration's tick period. 26 typedef duration::period period; 27 28 // An absolute time point represented using the clock. 29 typedef std::chrono::time_point<time_t_clock> time_point; 30 31 // The clock is not monotonically increasing. 32 static constexpr bool is_steady = false; 33 34 // Get the current time. nowtime_t_clock35 static time_point now() noexcept 36 { 37 return time_point() + std::chrono::seconds(std::time(0)); 38 } 39 }; 40 41 // The boost::asio::basic_waitable_timer template accepts an optional WaitTraits 42 // template parameter. The underlying time_t clock has one-second granularity, 43 // so these traits may be customised to reduce the latency between the clock 44 // ticking over and a wait operation's completion. When the timeout is near 45 // (less than one second away) we poll the clock more frequently to detect the 46 // time change closer to when it occurs. The user can select the appropriate 47 // trade off between accuracy and the increased CPU cost of polling. In extreme 48 // cases, a zero duration may be returned to make the timers as accurate as 49 // possible, albeit with 100% CPU usage. 50 struct time_t_wait_traits 51 { 52 // Determine how long until the clock should be next polled to determine 53 // whether the duration has elapsed. to_wait_durationtime_t_wait_traits54 static time_t_clock::duration to_wait_duration( 55 const time_t_clock::duration& d) 56 { 57 if (d > std::chrono::seconds(1)) 58 return d - std::chrono::seconds(1); 59 else if (d > std::chrono::seconds(0)) 60 return std::chrono::milliseconds(10); 61 else 62 return std::chrono::seconds(0); 63 } 64 65 // Determine how long until the clock should be next polled to determine 66 // whether the absoluate time has been reached. to_wait_durationtime_t_wait_traits67 static time_t_clock::duration to_wait_duration( 68 const time_t_clock::time_point& t) 69 { 70 return to_wait_duration(t - time_t_clock::now()); 71 } 72 }; 73 74 typedef boost::asio::basic_waitable_timer< 75 time_t_clock, time_t_wait_traits> time_t_timer; 76 main()77int main() 78 { 79 try 80 { 81 boost::asio::io_context io_context; 82 83 time_t_timer timer(io_context); 84 85 timer.expires_after(std::chrono::seconds(5)); 86 std::cout << "Starting synchronous wait\n"; 87 timer.wait(); 88 std::cout << "Finished synchronous wait\n"; 89 90 timer.expires_after(std::chrono::seconds(5)); 91 std::cout << "Starting asynchronous wait\n"; 92 timer.async_wait( 93 [](const boost::system::error_code& /*error*/) 94 { 95 std::cout << "timeout\n"; 96 }); 97 io_context.run(); 98 std::cout << "Finished asynchronous wait\n"; 99 } 100 catch (std::exception& e) 101 { 102 std::cout << "Exception: " << e.what() << "\n"; 103 } 104 105 return 0; 106 } 107