Skip to content

Commit 37ca549

Browse files
committed
refactor: spawn and spawn_local
1 parent 50b808e commit 37ca549

15 files changed

+137
-160
lines changed

README.md

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ I have also learned about some well-known C++20 coroutine open-source libraries,
103103
| Name | Description |
104104
|----------------------------------------------|-------------------------------------------------------|
105105
| `coro::async<T>` | Async task type, supports `co_await` and `co_return` |
106-
| `coro::co_spawn(executor, awaitable)` | Spawn a coroutine on an executor |
106+
| `coro::spawn(executor, awaitable)` | Spawn a coroutine on an executor |
107+
| `coro::spawn_local(awaitable)` | Spawn a coroutine on the current executor |
107108
| `coro::when_all(awaitables...) -> awaitable` | Wait for all tasks to complete |
108109
| `coro::when_any(awaitables...) -> awaitable` | Wait for any task to complete |
109110
| `coro::sleep(duration)` | Async wait for specified duration (chrono duration) |
@@ -185,15 +186,20 @@ async<void> process() {
185186

186187
int main() {
187188
executor_loop executor;
188-
189-
// Launch coroutine
190-
co_spawn(executor, process());
189+
190+
// Launch coroutine on specific executor
191+
spawn(executor, process());
191192
// Or: process().detach(executor);
192193

193194
// Run event loop
194195
executor.run_loop();
195196
return 0;
196197
}
198+
199+
// Using spawn_local inside coroutine
200+
async<void> main_task() {
201+
co_await spawn_local(process());
202+
}
197203
```
198204

199205
### Launch Coroutine with Callback
@@ -536,9 +542,8 @@ async<void> consumer(channel<int>& ch) {
536542
async<void> example() {
537543
channel<int> ch; // Unbuffered channel
538544

539-
auto& exec = *co_await current_executor();
540-
co_spawn(exec, producer(ch));
541-
co_spawn(exec, consumer(ch));
545+
co_await spawn_local(producer(ch));
546+
co_await spawn_local(consumer(ch));
542547
}
543548
```
544549
@@ -578,12 +583,10 @@ async<void> broadcast_example() {
578583
}
579584
};
580585

581-
auto& exec = *co_await current_executor();
582-
583586
// Spawn multiple receivers
584-
co_spawn(exec, receiver(ch, 1));
585-
co_spawn(exec, receiver(ch, 2));
586-
co_spawn(exec, receiver(ch, 3));
587+
co_await spawn_local(receiver(ch, 1));
588+
co_await spawn_local(receiver(ch, 2));
589+
co_await spawn_local(receiver(ch, 3));
587590

588591
// Broadcasting sends the value to ALL waiting receivers
589592
size_t notified_count = co_await ch.broadcast(42);
@@ -623,8 +626,8 @@ async<void> example() {
623626
wg.add(2);
624627

625628
// Launch worker coroutines
626-
co_spawn(executor, worker_task(wg, "Worker1", 100));
627-
co_spawn(executor, worker_task(wg, "Worker2", 150));
629+
spawn(executor, worker_task(wg, "Worker1", 100));
630+
spawn(executor, worker_task(wg, "Worker2", 150));
628631

629632
// Wait for all operations to complete
630633
co_await wg.wait();

README_CN.md

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@
8888
| 名称 | 说明 |
8989
|----------------------------------------------|------------------------------------|
9090
| `coro::async<T>` | 异步任务类型,支持 `co_await``co_return` |
91-
| `coro::co_spawn(executor, awaitable)` | 在执行器上启动协程 |
91+
| `coro::spawn(executor, awaitable)` | 在执行器上启动协程 |
92+
| `coro::spawn_local(awaitable)` | 在当前执行器上启动协程 |
9293
| `coro::when_all(awaitables...) -> awaitable` | 等待所有任务完成 |
9394
| `coro::when_any(awaitables...) -> awaitable` | 等待任意一个任务完成 |
9495
| `coro::sleep(duration)` | 异步等待指定时间(chrono duration) |
@@ -169,15 +170,20 @@ async<void> process() {
169170

170171
int main() {
171172
executor_loop executor;
172-
173-
// 启动协程
174-
co_spawn(executor, process());
173+
174+
// 在指定执行器上启动协程
175+
spawn(executor, process());
175176
// 或者: process().detach(executor);
176-
177+
177178
// 运行事件循环
178179
executor.run_loop();
179180
return 0;
180181
}
182+
183+
// 在协程内部使用 spawn_local 在当前执行器上启动协程
184+
async<void> main_task() {
185+
co_await spawn_local(process());
186+
}
181187
```
182188

183189
### 使用回调启动协程
@@ -520,9 +526,8 @@ async<void> consumer(channel<int>& ch) {
520526
async<void> example() {
521527
channel<int> ch; // 无缓冲 channel
522528

523-
auto& exec = *co_await current_executor();
524-
co_spawn(exec, producer(ch));
525-
co_spawn(exec, consumer(ch));
529+
co_await spawn_local(producer(ch));
530+
co_await spawn_local(consumer(ch));
526531
}
527532
```
528533
@@ -562,12 +567,10 @@ async<void> broadcast_example() {
562567
}
563568
};
564569

565-
auto& exec = *co_await current_executor();
566-
567570
// 启动多个接收者
568-
co_spawn(exec, receiver(ch, 1));
569-
co_spawn(exec, receiver(ch, 2));
570-
co_spawn(exec, receiver(ch, 3));
571+
co_await spawn_local(receiver(ch, 1));
572+
co_await spawn_local(receiver(ch, 2));
573+
co_await spawn_local(receiver(ch, 3));
571574

572575
// 广播将值发送给所有等待的接收者
573576
size_t notified_count = co_await ch.broadcast(42);
@@ -607,8 +610,8 @@ async<void> example() {
607610
wg.add(2);
608611

609612
// 启动工作协程
610-
co_spawn(executor, worker_task(wg, "Worker1", 100));
611-
co_spawn(executor, worker_task(wg, "Worker2", 150));
613+
spawn(executor, worker_task(wg, "Worker1", 100));
614+
spawn(executor, worker_task(wg, "Worker2", 150));
612615

613616
// 等待所有操作完成
614617
co_await wg.wait();

include/coro/coro.hpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ struct awaitable {
220220
}
221221

222222
/// co_await
223-
bool await_ready() const noexcept {
223+
[[nodiscard]] bool await_ready() const noexcept {
224224
CORO_DEBUG_LIFECYCLE("awaitable: await_ready: %p, h: %p", this, current_coro_handle_.address());
225225
return false;
226226
}
@@ -246,7 +246,7 @@ struct awaitable {
246246
return std::move(*this);
247247
}
248248

249-
executor* get_executor() const {
249+
[[nodiscard]] executor* get_executor() const {
250250
return current_coro_handle_.promise().executor_;
251251
}
252252

@@ -332,7 +332,7 @@ struct callback_awaiter : detail::callback_awaiter_base<T> {
332332
explicit callback_awaiter(callback_function_with_executor callback) : callback_function_(std::move(callback)) {}
333333
callback_awaiter(callback_awaiter&&) = default;
334334

335-
bool await_ready() const noexcept {
335+
[[nodiscard]] bool await_ready() const noexcept {
336336
return false;
337337
}
338338

@@ -382,7 +382,7 @@ struct callback_awaiter : detail::callback_awaiter_base<T> {
382382
namespace detail {
383383

384384
struct current_executor_awaiter {
385-
bool await_ready() const noexcept {
385+
[[nodiscard]] bool await_ready() const noexcept {
386386
return false;
387387
}
388388

@@ -392,7 +392,7 @@ struct current_executor_awaiter {
392392
return false;
393393
}
394394

395-
executor* await_resume() const noexcept {
395+
[[nodiscard]] executor* await_resume() const noexcept {
396396
return exec_;
397397
}
398398

@@ -402,16 +402,22 @@ struct current_executor_awaiter {
402402

403403
} // namespace detail
404404

405-
detail::current_executor_awaiter current_executor() {
405+
[[nodiscard]] detail::current_executor_awaiter current_executor() {
406406
return detail::current_executor_awaiter{};
407407
}
408408

409409
template <typename T>
410410
using async = awaitable<T>;
411411

412412
template <typename T>
413-
void co_spawn(executor& executor, T&& coro) {
413+
void spawn(executor& executor, T&& coro) {
414414
coro.detach(executor);
415415
}
416416

417+
template <typename T>
418+
[[nodiscard]] async<void> spawn_local(T&& awaitable) {
419+
auto* exec = co_await current_executor();
420+
spawn(*exec, std::forward<T>(awaitable));
421+
}
422+
417423
} // namespace coro

include/coro/time.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#include <chrono>
44
#include <cstdint>
55

6-
#include "coro/coro.hpp"
6+
#include "coro.hpp"
77

88
namespace coro {
99

test/coro_broadcast.cpp

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,10 @@ async<void> test_broadcast_multiple_receivers() {
3434
co_return;
3535
};
3636

37-
auto& exec = *co_await current_executor();
38-
3937
// Start 3 receivers
40-
co_spawn(exec, receiver(1, &receiver1_value, &receiver1_done));
41-
co_spawn(exec, receiver(2, &receiver2_value, &receiver2_done));
42-
co_spawn(exec, receiver(3, &receiver3_value, &receiver3_done));
38+
co_await spawn_local(receiver(1, &receiver1_value, &receiver1_done));
39+
co_await spawn_local(receiver(2, &receiver2_value, &receiver2_done));
40+
co_await spawn_local(receiver(3, &receiver3_value, &receiver3_done));
4341

4442
// Give receivers time to start waiting
4543
co_await sleep(50ms);
@@ -86,11 +84,9 @@ async<void> test_broadcast_vs_send() {
8684
co_return;
8785
};
8886

89-
auto& exec = *co_await current_executor();
90-
9187
// Start 2 receivers
92-
co_spawn(exec, receiver(1, &receiver1_value, &receiver1_done));
93-
co_spawn(exec, receiver(2, &receiver2_value, &receiver2_done));
88+
co_await spawn_local(receiver(1, &receiver1_value, &receiver1_done));
89+
co_await spawn_local(receiver(2, &receiver2_value, &receiver2_done));
9490

9591
co_await sleep(50ms);
9692

@@ -161,10 +157,8 @@ async<void> test_sequential_broadcasts() {
161157
co_return;
162158
};
163159

164-
auto& exec = *co_await current_executor();
165-
166-
co_spawn(exec, receiver(1, &receiver1_values));
167-
co_spawn(exec, receiver(2, &receiver2_values));
160+
co_await spawn_local(receiver(1, &receiver1_values));
161+
co_await spawn_local(receiver(2, &receiver2_values));
168162

169163
co_await sleep(50ms);
170164

test/coro_channel.cpp

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,8 @@ async<void> test_unbuffered_channel() {
7474
};
7575

7676
// Start producer first (it should block immediately)
77-
auto& exec = *co_await current_executor();
78-
co_spawn(exec, tracked_producer());
79-
co_spawn(exec, tracked_consumer());
77+
co_await spawn_local(tracked_producer());
78+
co_await spawn_local(tracked_consumer());
8079

8180
// Allow time for operations to complete
8281
co_await sleep(100ms);
@@ -161,9 +160,8 @@ async<void> test_buffered_channel() {
161160
co_return;
162161
};
163162

164-
auto& exec = *co_await current_executor();
165-
co_spawn(exec, tracked_producer());
166-
co_spawn(exec, tracked_consumer());
163+
co_await spawn_local(tracked_producer());
164+
co_await spawn_local(tracked_consumer());
167165

168166
// Wait for operations to complete
169167
co_await sleep(200ms);
@@ -198,8 +196,7 @@ async<void> test_channel_close() {
198196
receiver_completed = true;
199197
};
200198

201-
auto& exec = *co_await current_executor();
202-
co_spawn(exec, receiver());
199+
co_await spawn_local(receiver());
203200

204201
// Allow receiver to start waiting
205202
co_await sleep(10ms);
@@ -275,9 +272,8 @@ async<void> test_ping_pong() {
275272
co_return;
276273
};
277274

278-
auto& exec = *co_await current_executor();
279-
co_spawn(exec, server());
280-
co_spawn(exec, client());
275+
co_await spawn_local(server());
276+
co_await spawn_local(client());
281277

282278
co_await sleep(100ms);
283279

@@ -327,11 +323,10 @@ async<void> test_multiple_producers_consumers() {
327323
};
328324

329325
// Start 2 producers and 2 consumers
330-
auto& exec = *co_await current_executor();
331-
co_spawn(exec, producer(1, &producer1_completed));
332-
co_spawn(exec, producer(2, &producer2_completed));
333-
co_spawn(exec, consumer(1, &consumer1_completed));
334-
co_spawn(exec, consumer(2, &consumer2_completed));
326+
co_await spawn_local(producer(1, &producer1_completed));
327+
co_await spawn_local(producer(2, &producer2_completed));
328+
co_await spawn_local(consumer(1, &consumer1_completed));
329+
co_await spawn_local(consumer(2, &consumer2_completed));
335330

336331
#ifdef CORO_TEST_RUNNER_VERY_SLOW
337332
co_await sleep(300ms);

test/coro_condition_variable.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,8 @@ async<void> cv_producer_consumer_test() {
157157
co_return consumed;
158158
};
159159

160-
auto exec = co_await current_executor();
161-
co_spawn(*exec, producer(1));
162-
co_spawn(*exec, producer(2));
160+
co_await spawn_local(producer(1));
161+
co_await spawn_local(producer(2));
163162

164163
auto c1 = consumer(1);
165164
auto c2 = consumer(2);

0 commit comments

Comments
 (0)