|
| 1 | +# spawn |
| 2 | +* execution[meta header] |
| 3 | +* cpo[meta id-type] |
| 4 | +* std::execution[meta namespace] |
| 5 | +* cpp26[meta cpp] |
| 6 | + |
| 7 | +```cpp |
| 8 | +namespace std::execution { |
| 9 | + struct spawn_t { unspecified }; |
| 10 | + inline constexpr spawn_t spawn{}; |
| 11 | +} |
| 12 | +``` |
| 13 | +* unspecified[italic] |
| 14 | +
|
| 15 | +## 概要 |
| 16 | +`spawn`は、入力[Sender](sender.md)に対して[非同期トークンスコープ](scope_token.md))への関連付けを試み、成功時に入力Senderを早期開始(eagerly start)させるSenderコンシューマである。 |
| 17 | +
|
| 18 | +
|
| 19 | +## 効果 |
| 20 | +説明用の式`sndr`, `token`, `env`に対して、下記の通り定義する。 |
| 21 | +
|
| 22 | +- `Sndr`型を`decltype((sndr))`、 |
| 23 | +- `Token`型を[`remove_cvref_t`](/reference/type_traits/remove_cvref.md)`<decltype((token))>`、 |
| 24 | +- `Env`型を[`remove_cvref_t`](/reference/type_traits/remove_cvref.md)`<decltype((env))>`とする。 |
| 25 | +
|
| 26 | +[`sender`](sender.md)`<Sndr>`, [`scope_token`](scope_token.md)`<Token>`, [`queryable`](../queryable.md)`<Env>`のいずれかを満たさないとき、呼び出し式`spawn(sndr, token, env)`は不適格となる。 |
| 27 | +
|
| 28 | +そうでなければ、呼び出し式`spawn(sndr, token, env)`に対して、説明用の式`new_sender`を[`token.wrap`](scope_token.md)`(sndr)`とし、`alloc`と`senv`を次の通りとする。 |
| 29 | +
|
| 30 | +- 式[`get_allocator`](../get_allocator.md)`(env)`が適格なとき、`alloc`を[`get_allocator`](../get_allocator.md)`(env)`の結果、`senv`を式`env`とする。 |
| 31 | +- そうでなはく、式[`get_allocator`](../get_allocator.md)`(`[`get_env`](get_env.md)`(new_sender))`が適格なとき、`alloc`を[`get_allocator`](../get_allocator.md)`(`[`get_env`](get_env.md)`(new_sender))`の結果、`senv`を式[`JOIN-ENV`](../queryable.md)`(`[`prop`](prop.md)`(`[`get_allocator`](../get_allocator.md)`, alloc), env)`とする。 |
| 32 | +- そうではないとき、`alloc`を[`allocator`](/reference/memory/allocator.md)`<void>()`、`senv`を式`env`とする。 |
| 33 | +
|
| 34 | +呼び出し式`spawn(sndr, token, env)`は`void`型であり、次の効果をもつ。 |
| 35 | +
|
| 36 | +- `alloc`を用いてメモリ確保し、`alloc`, [`write_env`](write_env.md)`(token.wrap(sndr), senv)`, `token`から特殊化された`spawn-state`型のオブジェクト`o`を構築し、`o.run()`を呼び出す。何らかのオブジェクト構築・破棄時に例外送出されたときは、確保されたメモリが解放される。 |
| 37 | +
|
| 38 | +式`spawn(sndr, token)`は、式`spawn(sndr, token,` [`execution::env<>`](env.md)`())`と等価である。 |
| 39 | +
|
| 40 | +
|
| 41 | +## 説明専用エンティティ |
| 42 | +説明専用のクラス`spawn-state-base`を下記の通り定義する。 |
| 43 | +
|
| 44 | +```cpp |
| 45 | +namespace std::execution { |
| 46 | + struct spawn-state-base { // exposition only |
| 47 | + virtual void complete() noexcept = 0; // exposition only |
| 48 | + }; |
| 49 | +} |
| 50 | +``` |
| 51 | + |
| 52 | +説明専用のクラス`spawn-receiver`を下記の通り定義する。 |
| 53 | + |
| 54 | +```cpp |
| 55 | +namespace std::execution { |
| 56 | + struct spawn-receiver { // exposition only |
| 57 | + using receiver_concept = receiver_t; |
| 58 | + |
| 59 | + spawn-state-base* state; // exposition only |
| 60 | + void set_value() && noexcept { state->complete(); } |
| 61 | + void set_stopped() && noexcept { state->complete(); } |
| 62 | + }; |
| 63 | +} |
| 64 | +``` |
| 65 | +* receiver_t[link receiver.md] |
| 66 | +* spawn-state-base[italic] |
| 67 | + |
| 68 | +説明専用のクラステンプレート`spawn-state`を下記の通り定義する。 |
| 69 | + |
| 70 | +```cpp |
| 71 | +🔗 |
| 72 | +namespace std::execution { |
| 73 | + template<class Alloc, scope_token Token, sender Sender> |
| 74 | + struct spawn-state : spawn-state-base { // exposition only |
| 75 | + using op-t = connect_result_t<Sender, spawn-receiver>; // exposition only |
| 76 | + |
| 77 | + spawn-state(Alloc alloc, Sender&& sndr, Token token); // exposition only |
| 78 | + void complete() noexcept override; // exposition only |
| 79 | + void run(); // exposition only |
| 80 | + |
| 81 | + private: |
| 82 | + using alloc-t = // exposition only |
| 83 | + typename allocator_traits<Alloc>::template rebind_alloc<spawn-state>; |
| 84 | + |
| 85 | + alloc-t alloc; // exposition only |
| 86 | + op-t op; // exposition only |
| 87 | + Token token; // exposition only |
| 88 | + |
| 89 | + void destroy() noexcept; // exposition only |
| 90 | + }; |
| 91 | +} |
| 92 | +``` |
| 93 | +* scope_token[link scope_token.md] |
| 94 | +* sender[link sender.md] |
| 95 | +* connect_result_t[link connect_result_t.md] |
| 96 | +* allocator_traits[link /reference/memory/allocator_traits.md] |
| 97 | +* spawn-state-base[italic] |
| 98 | +* spawn-receiver[italic] |
| 99 | +
|
| 100 | +```cpp |
| 101 | +spawn-state(Alloc alloc, Sender&& sndr, Token token); |
| 102 | +``` |
| 103 | + |
| 104 | +- 効果 : メンバ変数`alloc`を引数`alloc`で、メンバ変数`token`を引数`token`で、`op`を下記で初期化する。 |
| 105 | + |
| 106 | + ```cpp |
| 107 | + connect(std::move(sndr), spawn-receiver(this)) |
| 108 | + ``` |
| 109 | + * connect[link connect.md] |
| 110 | + * std::move[link /reference/utility/move.md] |
| 111 | + |
| 112 | +```cpp |
| 113 | +void run(); |
| 114 | +``` |
| 115 | + |
| 116 | +- 効果 : 下記と等価 |
| 117 | + |
| 118 | + ```cpp |
| 119 | + if (token.try_associate()) |
| 120 | + start(op); |
| 121 | + else |
| 122 | + destroy(); |
| 123 | + ``` |
| 124 | + * start[link start.md] |
| 125 | + |
| 126 | +```cpp |
| 127 | +void complete() noexcept override; |
| 128 | +``` |
| 129 | + |
| 130 | +- 効果 : 下記と等価 |
| 131 | + |
| 132 | + ```cpp |
| 133 | + auto token = std::move(this->token); |
| 134 | + |
| 135 | + destroy(); |
| 136 | + token.disassociate(); |
| 137 | + ``` |
| 138 | + * std::move[link /reference/utility/move.md] |
| 139 | + |
| 140 | +```cpp |
| 141 | +void destroy() noexcept; |
| 142 | +``` |
| 143 | + |
| 144 | +- 効果 : 下記と等価 |
| 145 | + |
| 146 | + ```cpp |
| 147 | + auto alloc = std::move(this->alloc); |
| 148 | + |
| 149 | + allocator_traits<alloc-t>::destroy(alloc, this); |
| 150 | + allocator_traits<alloc-t>::deallocate(alloc, this, 1); |
| 151 | + ``` |
| 152 | + * allocator_traits[link /reference/memory/allocator_traits.md] |
| 153 | + * destroy[link /reference/memory/allocator_traits/destroy.md] |
| 154 | + * deallocate[link /reference/memory/allocator_traits/deallocate.md] |
| 155 | + * std::move[link /reference/utility/move.md] |
| 156 | + |
| 157 | + |
| 158 | +## 例 |
| 159 | +```cpp example |
| 160 | +#include <print> |
| 161 | +#include <execution> |
| 162 | +namespace ex = std::execution; |
| 163 | + |
| 164 | +int main() |
| 165 | +{ |
| 166 | + // システムスレッドプール上の実行タスクを定義 |
| 167 | + ex::scheduler auto sch = ex::get_parallel_scheduler(); |
| 168 | + ex::sender auto sndr = |
| 169 | + ex::schedule(sch) |
| 170 | + | ex::then([](){ std::println("hello async"); }); |
| 171 | + |
| 172 | + // 非同期スコープを定義 |
| 173 | + ex::counting_scope scope; |
| 174 | + |
| 175 | + // タスクを早期開始させる |
| 176 | + std::println("spawn"); |
| 177 | + ex::spawn(std::move(sndr), scope.get_token()); |
| 178 | + |
| 179 | + // 非同期スコープを合流 |
| 180 | + std::println("sync_wait"); |
| 181 | + std::this_thread::sync_wait(scope.join()); |
| 182 | +} |
| 183 | +``` |
| 184 | +* ex::spawn[color ff0000] |
| 185 | +* ex::scheduler[link scheduler.md] |
| 186 | +* ex::get_parallel_scheduler()[link get_parallel_scheduler.md] |
| 187 | +* ex::sender[link sender.md] |
| 188 | +* ex::schedule[link schedule.md] |
| 189 | +* ex::then[link then.md] |
| 190 | +* ex::counting_scope[link counting_scope.md] |
| 191 | +* get_token()[link counting_scope/get_token.md] |
| 192 | +* join()[link counting_scope/join.md] |
| 193 | +* std::this_thread::sync_wait[link ../this_thread/sync_wait.md] |
| 194 | +* std::move[link /reference/utility/move.md] |
| 195 | +
|
| 196 | +### 出力 |
| 197 | +``` |
| 198 | +spawn |
| 199 | +hello async |
| 200 | +sync_wait |
| 201 | +``` |
| 202 | +
|
| 203 | +
|
| 204 | +## バージョン |
| 205 | +### 言語 |
| 206 | +- C++26 |
| 207 | +
|
| 208 | +### 処理系 |
| 209 | +- [Clang](/implementation.md#clang): ?? |
| 210 | +- [GCC](/implementation.md#gcc): ?? |
| 211 | +- [ICC](/implementation.md#icc): ?? |
| 212 | +- [Visual C++](/implementation.md#visual_cpp): ?? |
| 213 | +
|
| 214 | +
|
| 215 | +## 関連項目 |
| 216 | +- [`execution::scope_token`](scope_token.md) |
| 217 | +- [`execution::spawn_future`](spawn_future.md.nolink) |
| 218 | +
|
| 219 | +
|
| 220 | +## 参照 |
| 221 | +- [P3149R11 `async_scope` - Creating scopes for non-sequential concurrency](https://open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3149r11.html) |
0 commit comments