Skip to content

Commit d01bc08

Browse files
committed
execution: P3149R11 spawn(#1510)
1 parent 7e196a7 commit d01bc08

File tree

9 files changed

+229
-8
lines changed

9 files changed

+229
-8
lines changed

reference/execution/execution.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ namespace std::execution {
140140
|------|------|----------------|
141141
| [`this_thread::sync_wait`](this_thread/sync_wait.md) | 現在のスレッド上でSender完了を待機 (customization point object) | C++26 |
142142
| [`this_thread::sync_wait_with_variant`](this_thread/sync_wait_with_variant.md) | 現在のスレッド上でSender完了を待機 (customization point object) | C++26 |
143-
| [`execution::spawn`](execution/spawn.md.nolink) | 非同期操作を早期開始 (customization point object) | C++26 |
143+
| [`execution::spawn`](execution/spawn.md) | 非同期操作を早期開始 (customization point object) | C++26 |
144144
145145
Senderコンシューマは名前空間 `std::this_thread` および名前空間 `std::execution` で定義される。
146146

reference/execution/execution/counting_scope/token/disassociate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ scope->disassociate()
4040
## 関連項目
4141
- [`execution::associate`](../../associate.md)
4242
- [`execution::spawn_future`](../../spawn_future.md.nolink)
43-
- [`execution::spawn`](../../spawn.md.nolink)
43+
- [`execution::spawn`](../../spawn.md)
4444

4545

4646
## 参照

reference/execution/execution/counting_scope/token/try_associate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ return scope->try-associate();
4040
## 関連項目
4141
- [`execution::associate`](../../associate.md)
4242
- [`execution::spawn_future`](../../spawn_future.md.nolink)
43-
- [`execution::spawn`](../../spawn.md.nolink)
43+
- [`execution::spawn`](../../spawn.md)
4444

4545

4646
## 参照

reference/execution/execution/counting_scope/token/wrap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ return stop-when(std::forward<Sender>(snd), scope->s_source.get_token());
4141
## 関連項目
4242
- [`execution::associate`](../../associate.md)
4343
- [`execution::spawn_future`](../../spawn_future.md.nolink)
44-
- [`execution::spawn`](../../spawn.md.nolink)
44+
- [`execution::spawn`](../../spawn.md)
4545

4646

4747
## 参照

reference/execution/execution/scope_token.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ int main()
7171
## 関連項目
7272
- [`execution::associate`](associate.md)
7373
- [`execution::spawn_future`](spawn_future.md.nolink)
74-
- [`execution::spawn`](spawn.md.nolink)
74+
- [`execution::spawn`](spawn.md)
7575

7676

7777
## 参照

reference/execution/execution/simple_counting_scope/token/disassociate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ scope->disassociate()
4040
## 関連項目
4141
- [`execution::associate`](../../associate.md)
4242
- [`execution::spawn_future`](../../spawn_future.md.nolink)
43-
- [`execution::spawn`](../../spawn.md.nolink)
43+
- [`execution::spawn`](../../spawn.md)
4444

4545

4646
## 参照

reference/execution/execution/simple_counting_scope/token/try_associate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ return scope->try-associate();
4040
## 関連項目
4141
- [`execution::associate`](../../associate.md)
4242
- [`execution::spawn_future`](../../spawn_future.md.nolink)
43-
- [`execution::spawn`](../../spawn.md.nolink)
43+
- [`execution::spawn`](../../spawn.md)
4444

4545

4646
## 参照

reference/execution/execution/simple_counting_scope/token/wrap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ Sender&& wrap(Sender&& snd) const noexcept;
3737
## 関連項目
3838
- [`execution::associate`](../../associate.md)
3939
- [`execution::spawn_future`](../../spawn_future.md.nolink)
40-
- [`execution::spawn`](../../spawn.md.nolink)
40+
- [`execution::spawn`](../../spawn.md)
4141

4242

4343
## 参照
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
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

Comments
 (0)