首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >"co_await other_co“和"other_co.resume”有什么区别?

"co_await other_co“和"other_co.resume”有什么区别?
EN

Stack Overflow用户
提问于 2022-06-05 03:12:54
回答 1查看 70关注 0票数 3

下面的代码不像我期望的那样工作。

代码语言:javascript
复制
#include <iostream>
#include <coroutine>
#include <vector>

struct symmetic_awaitable
{
    std::coroutine_handle<> _next_h;

    symmetic_awaitable(std::coroutine_handle<> h) : _next_h(h) {}

    constexpr bool await_ready() const noexcept { return false; }

    std::coroutine_handle<> await_suspend(std::coroutine_handle<>) const noexcept
    {
        return _next_h;
    }

    constexpr void await_resume() const noexcept {}
};

struct return_object : std::coroutine_handle<>
{
    struct promise_type
    {
        return_object get_return_object()
        {
            return std::coroutine_handle<promise_type>::from_promise(*this);
        }

        std::suspend_always initial_suspend() noexcept { return {}; }
        std::suspend_always final_suspend() noexcept { return {}; }
        void return_void() {}
        void unhandled_exception() {}
    };

    return_object(std::coroutine_handle<promise_type> h) : std::coroutine_handle<>(h) {}
};

std::vector<return_object> co_list;

return_object fa()
{
    std::cout << "fa1" << std::endl;
    co_await symmetic_awaitable(co_list[1]);
    std::cout << "fa2" << std::endl;
    co_return;
}

return_object fb()
{
    std::cout << "fb1" << std::endl;
    co_await symmetic_awaitable(co_list[2]);
    std::cout << "fb2" << std::endl;
    co_await std::suspend_always{};
    std::cout << "fb3" << std::endl;
    co_return;
}

return_object fc()
{
    std::cout << "fc1" << std::endl;
    co_await symmetic_awaitable(co_list[1]);
    std::cout << "fc2" << std::endl;
    co_return;
}

int main()
{
    auto a = fa();
    auto b = fb();
    auto c = fc();

    co_list.push_back(a);
    co_list.push_back(b);
    co_list.push_back(c);

    a.resume();
    std::cout << "end" << std::endl;

    a.destroy();
    b.destroy();
    c.destroy();
}

我认为输出将是

代码语言:javascript
复制
fa1
fb1
fc1
fb2
fa2
end

但实际产出是

代码语言:javascript
复制
fa1
fb1
fc1
fb2
end

然后我将所有的co_await symmetic_awaitable(co_list[i])替换为co_list[i].resume。这个排气管很奇怪

代码语言:javascript
复制
fa1
fb1
fc1
fb1
fc1
.....  // the following is infinite loop of "fb1 fc1"
.....
.....

C++20协同工作隐藏了太多的细节,除非我清楚地了解它们,否则代码就不能像我期望的那样正常工作。

以下是我在阅读cppreference后提出的问题:

1.“来电者”和“简历”的区别是什么?

一个呼叫b.resume(),那么a是b的简历还是调用者?

2.“暂停”的确切含义是什么?

一个呼叫b.resume(),然后一个是挂起还是正在运行?一份简历b通过co_await,然后a被挂起还是运行?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-05 03:47:03

如果一个函数是一个协同线,它只能以下列方式之一被挂起:

  1. 当协同线启动时,如果承诺最初中止。
  2. co_await表达式(或等效的,如co_yield)被直接调用;
  3. ,当coroutine co_returns时,如果承诺最终中止。

G 210

其他任何东西都不能使一条协同线被暂停。"coroutine“中的"co”代表合作多任务处理。这意味着,除非涉及的功能合作,否则不存在多任务处理。明文规定。

您对代码工作方式的假设似乎表明,您认为协同机制具有某种执行堆栈。当调用await_suspend时,当前协同线将被放入堆栈中,当返回的协同线句柄以某种方式结束时,堆栈将被弹出。因此,当您调用co_await std::suspend_always{};时,这将恢复以前挂起的协同线。

所有这些都不是真的。除非你自己制造那台机器。

协同系统只做你让它做的事。

调用a.resume()后的调用堆栈如下所示:

代码语言:javascript
复制
main()
fa()

fa挂起并恢复fb时,现在看起来如下所示:

代码语言:javascript
复制
main()
fb()

fa走了。你把它暂停了。它不再在调用堆栈上。只有当你明确要求恢复它时,它才会被恢复。

如果你想让fa暂停进入fb意味着fafb完成后还会继续,那么你必须在你的协同机制中安装它。它不仅仅发生,你有责任让它发生。

您的await_suspend代码需要获得给定的句柄(它指的是fa),并将其存储在一个地方,当fb完成时,它可以恢复fa。这通常在fb的承诺对象中,这样final_suspend就可以恢复它(通常是传递由fb生成的数据)。记住:无论承诺的final_suspend返回什么,最后的挂起点都将co_await,所以您可以返回您想要恢复的协同线的句柄。

“来电者”和“简历”的区别是什么?

我不知道那是什么意思。我怀疑您是在问co_await在某件事情上的作用与直接调用coroutine_handle::resume函数之间的区别。

如前所述,在初始和最终挂起点之外,只有co_await (或等效的)表达式才能导致协同线挂起。调用句柄上的resume就像调用函数的中间一样。它就像任何其他函数调用一样工作;它进入堆栈,依此类推。

拥有co_await简历是不同的。当await_suspend返回一个协同线句柄时,这将用调用堆栈上恢复的协同线替换您的协同线。这就是暂停合作线的全部意义。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72504525

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档