Skip to content

当使用无栈协程在库中实现一个功能时,我们需要为该功能提供多种接口以供不同的用户的使用。 例如,我们使用无栈协程实现了一个 Read 功能。

cpp
Lazy<size_t> Read();

但调用者可能为无栈协程、有栈协程或者普通函数,由于无栈协程存在传染性,此时该如何做呢?

无栈协程

当调用者为无栈协程时,不需要额外封装,使用 co_await 调用即可:

cpp
Lazy<size_t> foo() {
    auto val = co_await Read();
    // ...
}

有栈协程

当调用者为有栈协程时,可以使用 await 方法封装 Read 方法。

cpp
Lazy<size_t> Read();
Future<size_t> ReadAsync() {
    return await(nullptr, Read);
}
void foo() { // in Uthread
    auto val = ReadAsync().get();
    // ...
}

await

await 方法用于有栈协程异步等待无栈协程时。await 有以下两个重载:

Class member method

cpp
template <class B, class Fn, class C, class... Ts>
decltype(auto) await(Executor* ex, Fn B::* fn, C* cls, Ts&&... ts);

若 Fn 返回类型为 Lazy<T>,则 await 返回值为 T。

使用场景为

cpp
class Foo {
public:
   lazy<T> bar(int a, int b) {}
};
Foo f;
await(ex, &Foo::bar, &f, a, b);

其中 ex 为指定的调度器,若无可设为 nullptr。

Normal Method

cpp
template <class Fn, class... Ts>
decltype(auto) await(Executor* ex, Fn&& fn, Ts&&... ts);

若 Fn 返回类型为 Lazy<T>,则 await 返回值为 T。

使用场景为

cpp
lazy<T> foo(Ts&&...);
await(ex, foo, Ts&&...);
auto lambda = [](Ts&&...) -> lazy<T> {
    // ...
};
await(ex, lambda, Ts&&...);

其中 ex 为指定的调度器,若无可设为 nullptr。

普通函数

普通函数可以使用 syncAwait 封装无栈协程:

cpp
Lazy<size_t> Read();
size_t ReadSync() {
    return syncAwait(Read());
}
void foo() {
    auto val = ReadSync();
    // ...
}

若需要为无栈协程指定调度器,可:

cpp
Lazy<size_t> Read();
size_t ReadSync(Executor* ex) {
    return syncAwait(Read().via(ex));
}
void foo() {
    auto *ex = getExecutor();
    auto val = ReadSync(ex);
    // ...
}

异步非阻塞调用

无论普通函数、有栈协程或者是无栈协程,都可以使用 .start 方式异步非阻塞地调用协程:

cpp
Lazy<size_t> Read();
void ReadCallback(std::function<void(Try<size_t>)> callback) {
    Read().start(callback);
}
void foo() {
    ReadCallback(callback);
    // continue to execute immediately.
}

This website is released under the MIT License.