C++协程中final_suspend的awaiter的实际规则是什么?

问题描述 投票:0回答:1

在 C++ 协程中,promise 类型的

final_suspend
成员函数可以返回任意可等待类型,但通常是
std::suspend_always
将销毁协程的责任留给其他人,或者
std::suspend_never
自动销毁协程。后者似乎是一种特殊情况,因为通常不允许恢复处于最终挂起点的协程。但在我的测试中,似乎这种特殊行为并没有统一应用。

问题的关键在于可等待的

await_suspend
成员函数可以具有三种不同返回类型中的任何一种:如果它返回
void
,则协程将保持挂起状态。如果它返回
bool
,则协程将恢复
false
并保持暂停状态
true
。如果它返回
std::coroutine_handle
,则该协程将恢复。

我已经用

final_suspend
的返回值测试了所有这些结果的行为,并且 MSVC、Clang 和 GCC 的所有三个都集中在这种行为上,以实现可等待,其中
await_ready
始终返回
false

  1. 如果
    final_suspend().await_suspend(handle)
    返回
    void
    ,则协程将按预期保持在其最终暂停点暂停。
  2. 如果
    final_suspend().await_suspend(handle)
    返回
    bool(true)
    ,在这种情况下,协程也会在其最终暂停点保持暂停状态。
  3. 如果
    final_suspend().await_suspend(handle)
    返回
    bool(false)
    ,有趣的是,协程会自动销毁,从正在执行的 Promise 类型的析构函数可以看出。这与
    std::suspend_never
    的行为一致,并表明可以在运行时做出决定。另外值得注意的是,
    await_resume
    也在销毁协程之前被调用,尽管它的结果被丢弃了。
  4. 如果
    final_suspend().await_suspend(handle)
    返回另一个协程的句柄,则该协程将按预期恢复,并且当前协程在其最终挂起点保持挂起状态。
  5. 如果
    final_suspend().await_suspend(handle)
    返回与给定的句柄相同的句柄,则程序崩溃!

结果 1、2 和 4 符合预期。结果 3 和 5 是我最感兴趣的 - 从某个角度来看,你会认为它们会受到相同的对待,因为在这两种情况下,它们都试图“恢复”已完成的协程,但只有结果 3 似乎得到了特殊处理用于自动销毁协程。这使得在返回协程句柄时在运行时决定这一点有点尴尬,因为您必须手动销毁协程,然后返回一个无操作的协程句柄,这比简单地返回

false
更复杂一点相同的效果,甚至可能由于必须返回类型擦除的句柄而使某些用例变得不可能。

我的问题是,C++ 标准中到底在哪里描述或规定了这些具体结果?当我看的时候,我找不到太多。该标准对协程行为的描述显得相当简短。

final_suspend
的可等待的特殊行为似乎很重要,但我找不到它。我可以找到一个声明,
final_suspend
及其可等待的使用必须是
noexcept
(“不得潜在地抛出”),但就我能找到的特殊规则而言,这就是关于它的。我缺少哪一部分?为什么返回传入的相同句柄会导致与返回
false
不同的行为?

c++ language-lawyer c++20 c++-coroutine
1个回答
0
投票

await_suspend
返回
false
时,协程恢复。这会导致控制从协程末端流出,从而破坏了协程状态

await_suspend
返回句柄时,会在该句柄上调用
resume()
。这违反了
resume()前提条件
,因此行为未定义。

© www.soinside.com 2019 - 2024. All rights reserved.