15 Timers [timer]

This clause defines components for performing timer operations.

Example: Performing a synchronous wait operation on a timer:

io_context c;
steady_timer t(c);
t.expires_after(seconds(5));
t.wait();

 — end example ]

Example: Performing an asynchronous wait operation on a timer:

void handler(error_code ec) { ... }
...
io_context c;
steady_timer t(c);
t.expires_after(seconds(5));
t.async_wait(handler);
c.run();

 — end example ]

15.1 Header <experimental/timer> synopsis [timer.synop]

#include <chrono>

namespace std {
namespace experimental {
namespace net {
inline namespace v1 {

  template<class Clock> struct wait_traits;

  template<class Clock, class WaitTraits = wait_traits<Clock>>
    class basic_waitable_timer;

  using system_timer = basic_waitable_timer<chrono::system_clock>;
  using steady_timer = basic_waitable_timer<chrono::steady_clock>;
  using high_resolution_timer = basic_waitable_timer<chrono::high_resolution_clock>;

} // inline namespace v1
} // namespace net
} // namespace experimental
} // namespace std

15.2 Requirements [timer.reqmts]

15.2.1 Wait traits requirements [timer.reqmts.waittraits]

The basic_waitable_timer template uses wait traits to allow programs to customize wait and async_wait behavior. [ Note: Possible uses of wait traits include:

  • To enable timers based on non-realtime clocks.

  • Determining how quickly wallclock-based timers respond to system time changes.

  • Correcting for errors or rounding timeouts to boundaries.

  • Preventing duration overflow. That is, a program can set a timer's expiry e to be Clock::max() (meaning never reached) or Clock::min() (meaning always in the past). As a result, computing the duration until timer expiry as e - Clock::now() can cause overflow.

 — end note ]

For a type Clock meeting the Clock requirements (C++ 2014 [time.clock.req]), a type X meets the WaitTraits requirements if it satisfies the requirements listed below.

In Table [tab:timer.reqmts.waittraits.requirements], t denotes a (possibly const) value of type Clock::time_point; and d denotes a (possibly const) value of type Clock::duration.

Table 11 — WaitTraits requirements
expressionreturn typeassertion/note pre/post-condition
X::to_wait_duration(d) Clock::duration Returns a Clock::duration value to be used in a wait or async_wait operation. [ Note: The return value is typically representative of the duration d.  — end note ]
X::to_wait_duration(t) Clock::duration Returns a Clock::duration value to be used in a wait or async_wait operation. [ Note: The return value is typically representative of the duration from Clock::now() until the time point t.  — end note ]

15.3 Class template wait_traits [timer.waittraits]

namespace std {
namespace experimental {
namespace net {
inline namespace v1 {

  template<class Clock>
  struct wait_traits
  {
    static typename Clock::duration to_wait_duration(
      const typename Clock::duration& d);

    static typename Clock::duration to_wait_duration(
      const typename Clock::time_point& t);
  };

} // inline namespace v1
} // namespace net
} // namespace experimental
} // namespace std

Class template wait_traits satisfies the WaitTraits ([timer.reqmts.waittraits]) type requirements. Template argument Clock is a type meeting the Clock requirements (C++ 2014 [time.clock.req]).

static typename Clock::duration to_wait_duration( const typename Clock::duration& d);

Returns: d.

static typename Clock::duration to_wait_duration( const typename Clock::time_point& t);

Returns: Let now be Clock::now(). If now + Clock::duration::max() is before t, Clock::duration::max(); if now + Clock::duration::min() is after t, Clock::duration::min(); otherwise, t - now.

15.4 Class template basic_waitable_timer [timer.waitable]

namespace std {
namespace experimental {
namespace net {
inline namespace v1 {

  template<class Clock, class WaitTraits = wait_traits<Clock>>
  class basic_waitable_timer
  {
  public:
    // types:

    using executor_type = io_context::executor_type;
    using clock_type = Clock;
    using duration = typename clock_type::duration;
    using time_point = typename clock_type::time_point;
    using traits_type = WaitTraits;

    // [timer.waitable.cons], construct / copy / destroy:

    explicit basic_waitable_timer(io_context& ctx);
    basic_waitable_timer(io_context& ctx, const time_point& t);
    basic_waitable_timer(io_context& ctx, const duration& d);
    basic_waitable_timer(const basic_waitable_timer&) = delete;
    basic_waitable_timer(basic_waitable_timer&& rhs);

    ~basic_waitable_timer();

    basic_waitable_timer& operator=(const basic_waitable_timer&) = delete;
    basic_waitable_timer& operator=(basic_waitable_timer&& rhs);

    // [timer.waitable.ops], basic_waitable_timer operations:

    executor_type get_executor() noexcept;

    size_t cancel();
    size_t cancel_one();

    time_point expiry() const;
    size_t expires_at(const time_point& t);
    size_t expires_after(const duration& d);

    void wait();
    void wait(error_code& ec);

    template<class CompletionToken>
      DEDUCED async_wait(CompletionToken&& token);
  };

} // inline namespace v1
} // namespace net
} // namespace experimental
} // namespace std

Instances of class template basic_waitable_timer meet the requirements of Destructible (C++ 2014 [destructible]), MoveConstructible (C++ 2014 [moveconstructible]), and MoveAssignable (C++ 2014 [moveassignable]).

15.4.1 basic_waitable_timer constructors [timer.waitable.cons]

explicit basic_waitable_timer(io_context& ctx);

Effects: Equivalent to basic_waitable_timer(ctx, time_point()).

basic_waitable_timer(io_context& ctx, const time_point& t);

Postconditions:

  • get_executor() == ctx.get_executor().

  • expiry() == t.

basic_waitable_timer(io_context& ctx, const duration& d);

Effects: Sets the expiry time as if by calling expires_after(d).

Postconditions: get_executor() == ctx.get_executor().

basic_waitable_timer(basic_waitable_timer&& rhs);

Effects: Move constructs an object of class basic_waitable_timer<Clock, WaitTraits> that refers to the state originally represented by rhs.

Postconditions:

  • get_executor() == rhs.get_executor().

  • expiry() returns the same value as rhs.expiry() prior to the constructor invocation.

  • rhs.expiry() == time_point().

15.4.2 basic_waitable_timer destructor [timer.waitable.dtor]

~basic_waitable_timer();

Effects: Destroys the timer, canceling any asynchronous wait operations associated with the timer as if by calling cancel().

15.4.3 basic_waitable_timer assignment [timer.waitable.assign]

basic_waitable_timer& operator=(basic_waitable_timer&& rhs);

Effects: Cancels any outstanding asynchronous operations associated with *this as if by calling cancel(), then moves into *this the state originally represented by rhs.

Postconditions:

  • get_executor() == rhs.get_executor().

  • expiry() returns the same value as rhs.expiry() prior to the assignment.

  • rhs.expiry() == time_point().

Returns: *this.

15.4.4 basic_waitable_timer operations [timer.waitable.ops]

executor_type get_executor() noexcept;

Returns: The associated executor.

size_t cancel();

Effects: Causes any outstanding asynchronous wait operations to complete. Completion handlers for canceled operations are passed an error code ec such that ec == errc::operation_canceled yields true.

Returns: The number of operations that were canceled.

Remarks: Does not block (C++ 2014 [defns.block]) the calling thread pending completion of the canceled operations.

size_t cancel_one();

Effects: Causes the outstanding asynchronous wait operation that was initiated first, if any, to complete as soon as possible. The completion handler for the canceled operation is passed an error code ec such that ec == errc::operation_canceled yields true.

Returns: 1 if an operation was canceled, otherwise 0.

Remarks: Does not block (C++ 2014 [defns.block]) the calling thread pending completion of the canceled operation.

time_point expiry() const;

Returns: The expiry time associated with the timer, as previously set using expires_at() or expires_after().

size_t expires_at(const time_point& t);

Effects: Cancels outstanding asynchronous wait operations, as if by calling cancel(). Sets the expiry time associated with the timer.

Returns: The number of operations that were canceled.

Postconditions: expiry() == t.

size_t expires_after(const duration& d);

Returns: expires_at(clock_type::now() + d).

void wait(); void wait(error_code& ec);

Effects: Establishes the postcondition as if by repeatedly blocking the calling thread (C++ 2014 [defns.block]) for the relative time produced by WaitTraits::to_wait_duration(expiry()).

Postconditions: ec || expiry() <= clock_type::now().

template<class CompletionToken> DEDUCED async_wait(CompletionToken&& token);

Completion signature: void(error_code ec).

Effects: Initiates an asynchronous wait operation to repeatedly wait for the relative time produced by WaitTraits::to_wait_duration(e), where e is a value of type time_point such that e <= expiry(). The completion handler is submitted for execution only when the condition ec || expiry() <= clock_type::now() yields true.

Note: To implement async_wait, an io_context object ctx could maintain a priority queue for each specialization of basic_waitable_timer<Clock, WaitTraits> for which a timer object was initialized with ctx. Only the time point e of the earliest outstanding expiry need be passed to WaitTraits::to_wait_duration(e).  — end note ]