diff --git a/docs/coroutine/cancellable.md b/docs/coroutine/cancellable.md index e076bf6..924b43a 100644 --- a/docs/coroutine/cancellable.md +++ b/docs/coroutine/cancellable.md @@ -2,7 +2,7 @@ ## 原理 -标准[coroutine](https://en.cppreference.com/w/cpp/language/coroutines)机制中的`co_await`相当于`std::future::get`方法,即等待目标awaitable完成,并在之后才能恢复执行;但有时需要让等待具备提前结束的能力,最为典型的场景是timeout这类场景; +标准[coroutine](https://en.cppreference.com/w/cpp/language/coroutines)机制中的`co_await`相当于[std::future::get](https://en.cppreference.com/w/cpp/thread/future/get)方法,即等待目标awaitable完成,并在之后才能恢复执行;但有时需要让等待具备提前结束的能力,最为典型的场景是timeout这类场景; ![](images/cancellable.png) diff --git a/docs/coroutine/futex.md b/docs/coroutine/futex.md new file mode 100644 index 0000000..de5f50a --- /dev/null +++ b/docs/coroutine/futex.md @@ -0,0 +1,48 @@ +# futex + +## 原理 + +标准[coroutine](https://en.cppreference.com/w/cpp/language/coroutines)机制中的`co_await`基本对标了[std::future](https://en.cppreference.com/w/cpp/thread/future)并行同步模式;但更多复杂的同步模式例如[std::mutex](https://en.cppreference.com/w/cpp/thread/mutex)或者[std::condition_variable](https://en.cppreference.com/w/cpp/thread/condition_variable)的支持可以统一通过类似[futex(2)](https://man7.org/linux/man-pages/man2/futex.2.html)的机制统一支持; + +![](images/futex.png) + +实现上通过每个futex实例伴随一个`std::mutex`来实现值检测和等待回调链串联原子性;通过[DepositBox](../concurrent/deposit_box.md)实现取消和唤醒的唯一性; + +## 用法示例 + +```c++ +#include "babylon/coroutine/task.h" +#include "babylon/coroutine/futex.h" + +using ::babylon::coroutine::Task; +using ::babylon::coroutine::Futex; + +using Cancellation = Futex::Cancellation; + +// Futex构造时内部值为0 +Futex futex; + +// 读写futex内部值 +futex.value() = ... +// 原子式读写futex内部值 +futex.atomic_value().xxxx(...); + +Task<...> some_coroutine(...) { + ... + // 原子检测内部值是否为expected_value,是则挂起some_coroutine,否则直接继续执行 + co_await futex.wait(expected_value).on_suspend( + // 通过回调函数在协程挂起后接收相应的取消句柄 + // 注意,如果协程未经历挂起,回调不会被调用 + [&](Cancellation cancel) { + // 典型操作是把cancel句柄注册到某种timer机制,并在指定时间后调用cancel()发起取消 + // 从回调被执行开始,cancel就可用了,甚至在回调内部也可以直接发起cancel(),虽然一般这并没有什么意义 + on_timer(cancel, 100ms); + } + ); + // 有种可能执行到这里 + // 1. 未满足expected_value + // 2. 挂起后futex.wake_one或者futex.wake_all被调用 + // 3. 挂起后cancel()被调用 + ... +} +``` diff --git a/docs/coroutine/images/cancellable.png b/docs/coroutine/images/cancellable.png index fdbdbb4..aed111f 100644 Binary files a/docs/coroutine/images/cancellable.png and b/docs/coroutine/images/cancellable.png differ diff --git a/docs/coroutine/images/futex.png b/docs/coroutine/images/futex.png new file mode 100644 index 0000000..cf78e92 Binary files /dev/null and b/docs/coroutine/images/futex.png differ diff --git a/src/babylon/coroutine/futex.h b/src/babylon/coroutine/futex.h index c0cbe79..afd3534 100644 --- a/src/babylon/coroutine/futex.h +++ b/src/babylon/coroutine/futex.h @@ -15,6 +15,13 @@ class Futex { class Awaitable; class Cancellation; + inline Futex() noexcept = default; + Futex(Futex&&) = delete; + Futex(const Futex&&) = delete; + Futex& operator=(Futex&&) = delete; + Futex& operator=(const Futex&&) = delete; + inline ~Futex() noexcept = default; + // Get the futex word to manipulate inline uint64_t& value() noexcept; inline ::std::atomic& atomic_value() noexcept;