mp-coro main
Coroutine support tools
synchronized_task.h
Go to the documentation of this file.
1// The MIT License (MIT)
2//
3// Copyright (c) 2021 Mateusz Pusz
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#pragma once
24
27#include <mp-coro/coro_ptr.h>
28#include <mp-coro/trace.h>
29#include <mp-coro/type_traits.h>
30#include <coroutine>
31
32namespace mp_coro::detail {
33
34/// Lazy task that can later be started explicitly, and that notifies another
35/// variable (the “sync” object) of its completion.
36/// This class doesn't spawn any threads itself, it just defines a coroutine
37/// with the notification of the “sync” object as its continuation.
38template <sync_notification_type Sync, task_value_type T>
39class [[nodiscard]] synchronized_task {
40 public:
41 /// The type of the value produced by this @ref synchronized_task.
42 using value_type = T;
43
44 /// Required promise type for coroutines returning a @ref synchronized_task.
45 /// Stores the value produced by the @ref synchronized_task, and a pointer
46 /// to the “sync” object, a variable to notify after completion of the
47 /// @ref synchronized_task.
49 /// Pointer to the “sync” object to notify of our completion.
50 Sync *sync = nullptr;
51
52 /// Returns a @ref synchronized_task that references this promise.
54 TRACE_FUNC();
55 return this;
56 }
57
58 /// Lazy: not started until @ref start() is invoked explicitly.
59 static std::suspend_always initial_suspend() noexcept {
60 TRACE_FUNC();
61 return {};
62 }
63
64 /// Awaiter returned by @ref final_suspend.
65 struct final_awaiter : std::suspend_always {
66 void await_suspend(std::coroutine_handle<promise_type> this_coro) noexcept {
67 TRACE_FUNC();
68 this_coro.promise().sync->notify_awaitable_completed();
69 }
70 };
71
72 /// When awaited, notifies the “sync” object (@ref sync) of this
73 /// @ref synchronized_task's completion.
74 static awaiter_of<void> auto final_suspend() noexcept {
75 TRACE_FUNC();
76 return final_awaiter {};
77 }
78 };
79
80 synchronized_task(synchronized_task &&) = default; ///< Move constructor
81 synchronized_task &operator=(synchronized_task &&) = delete; ///< Move assignment not allowed.
82
83 /// Start (resume) execution of the @ref synchronized_task.
84 /// @param s
85 /// Reference to the “sync” object, i.e. the variable to notify of
86 /// the %task's completion. When the %task is suspended at its final
87 /// suspension point, `s.notify_awaitable_completed()` is called.
88 /// @note `s.notify_awaitable_completed()` is called directly in
89 /// @ref promise_type::final_awaiter::await_suspend(), it does not
90 /// (and cannot) use Symmetric Control Transfer.
91 void start(Sync &s) {
92 promise_->sync = &s;
93 std::coroutine_handle<promise_type>::from_promise(*promise_).resume();
94 }
95
96 /// Get the value produced by this %task.
97 /// Must be called after the “sync” object passed to @ref start() has been
98 /// notified.
99 [[nodiscard]] decltype(auto) get() const & {
100 TRACE_FUNC();
101 return promise_->get();
102 }
103 /// @copydoc get()const&
104 [[nodiscard]] decltype(auto) get() const && {
105 TRACE_FUNC();
106 return std::move(*promise_).get();
107 }
108 /// @copydoc get()const&
109 [[nodiscard]] decltype(auto) nonvoid_get() const & {
110 TRACE_FUNC();
111 return promise_->nonvoid_get();
112 }
113 /// @copydoc get()const&
114 [[nodiscard]] decltype(auto) nonvoid_get() const && {
115 TRACE_FUNC();
116 return std::move(*promise_).nonvoid_get();
117 }
118
119 private:
120 /// An owning pointer to the promise object in the coroutine frame.
121 /// When the task is destructed, this will cause the coroutine frame to be
122 /// destroyed automatically.
124
125 /// Private constructor used in @ref promise_type::get_return_object.
126 synchronized_task(promise_type *promise) : promise_(promise) { TRACE_FUNC(); }
127};
128
129/// Coroutine returning an @ref synchronized_task that awaits the given
130/// awaitable and returns its result.
131///
132/// @relates synchronized_task
133template <sync_notification_type Sync, awaitable A>
134synchronized_task<Sync, remove_rvalue_reference_t<await_result_t<A>>>
136 TRACE_FUNC();
137 co_return co_await std::forward<A>(awaitable);
138}
139
140} // namespace mp_coro::detail
Lazy task that can later be started explicitly, and that notifies another variable (the “sync” object...
decltype(auto) get() const &
Get the value produced by this task.
decltype(auto) nonvoid_get() const &&
Get the value produced by this task.
decltype(auto) get() const &&
Get the value produced by this task.
promise_ptr< promise_type > promise_
An owning pointer to the promise object in the coroutine frame.
synchronized_task & operator=(synchronized_task &&)=delete
Move assignment not allowed.
decltype(auto) nonvoid_get() const &
Get the value produced by this task.
synchronized_task< Sync, remove_rvalue_reference_t< await_result_t< A > > > make_synchronized_task(A &&awaitable)
Coroutine returning an synchronized_task that awaits the given awaitable and returns its result.
void start(Sync &s)
Start (resume) execution of the synchronized_task.
synchronized_task(synchronized_task &&)=default
Move constructor.
synchronized_task(promise_type *promise)
Private constructor used in promise_type::get_return_object.
T value_type
The type of the value produced by this synchronized_task.
std::unique_ptr< T, coro_deleter > promise_ptr
RAII wrapper that destroys promise object's associated coroutine.
Definition: coro_ptr.h:44
Base class with deleted copy constructor and copy assignment operator.
Definition: noncopyable.h:28
void await_suspend(std::coroutine_handle< promise_type > this_coro) noexcept
Required promise type for coroutines returning a synchronized_task.
synchronized_task get_return_object() noexcept
Returns a synchronized_task that references this promise.
static awaiter_of< void > auto final_suspend() noexcept
When awaited, notifies the “sync” object (sync) of this synchronized_task's completion.
static std::suspend_always initial_suspend() noexcept
Lazy: not started until start() is invoked explicitly.
#define TRACE_FUNC()
Definition: trace.h:27