gpt4 book ai didi

Why coroutine_handle.done cannot return correct result?(为什么coroutine_handle.one不能返回正确的结果?)

转载 作者:bug小助手 更新时间:2023-10-25 14:53:02 24 4
gpt4 key购买 nike



I'm currently learning about coroutine in c++20. I encountered a problem. Here is my code:

我目前正在学习C++20中的协程。我遇到了一个问题。以下是我的代码:


//coroutine return object definition
class ReturnObject {
public:
struct promise_type {
std::suspend_never initial_suspend() { return {}; }
std::suspend_never final_suspend() noexcept {
return {};
}
ReturnObject get_return_object() { return ReturnObject(*this); }
std::suspend_always yield_value(int val)
{
m_value = val;
return std::suspend_always{};
}
void unhandled_exception() {}
void return_void() {}
private:
int m_value;
public:
int GetValue() const { return m_value; }
};
private:
std::coroutine_handle<promise_type> m_handle;
public:
decltype(m_handle) Handle() { return m_handle; }
ReturnObject(promise_type& promise) : m_handle(std::coroutine_handle<promise_type>::from_promise(promise)){}
int GetValue() const { return m_handle.promise().GetValue(); }
};

//range generator
ReturnObject Range(int startInc, int endInc, int step = 1)
{
for (int i = startInc; i <= endInc; i += step)
{
co_yield i;
}
}

//main function
int main()
{
ReturnObject range = Range(1,10,3);
while (!range.Handle().done())
{
std::cout << range.GetValue() << std::endl;
range.Handle().resume();
}
}


I found that the while-loop cannot quit correctly and it results in a runtime error. Could someone tell me why?

我发现While循环不能正确退出,并导致运行时错误。有人能告诉我为什么吗?


更多回答

your final_suspend is suspend_never, so the coroutine self-destructs when it completes, and the handle becomes invalid. You then try to use that handle (to check its done()) and that is UB. done() returns true if the coroutine is suspended at its final suspension point, but your coroutine is not suspended at its final suspension point. It has executed past its final suspension point. You should make final_suspend return suspend_always, and then after the loop exits, manually .destroy() the coroutine handle.

您的FINAL_SUSPEND是SUSPEND_NEVER,所以协程在完成时会自毁,句柄也会失效。然后尝试使用该句柄(检查其完成()),这就是UB。如果协程在其最终挂起点处挂起,则Done()返回True,但协程未在其最终挂起点处挂起。它的执行已经超过了最后的停止点。您应该使FINAL_SUSPEND返回SUSPEND_ALWAYS,然后在循环退出后,手动地对协程句柄执行.store()。

优秀答案推荐

A coroutine_handle is like a raw pointer to the coroutine frame. In particular, like a raw pointer, the coroutine_handle does not have ownership and can become dangling if the coroutine frame goes away. That is what is happening here when Range() has completed its for-loop.

协程句柄就像指向协程框架的原始指针。特别是,就像原始指针一样,coroutine_Handle没有所有权,如果coroutine框架消失,它可能会变得悬空。当range()完成其for循环时,这里就会发生这种情况。


The done() method is particularly misleading in this regard, as the name suggests that it is able to indicate whether the coroutine_handle is still valid. That is not the case! The same is true for the operator bool() on the coroutine_handle.

done()方法在这方面特别容易引起误解,因为它的名字暗示它能够指示coroutine_handle是否仍然有效。不是这样的!对于协程句柄上的操作符bool()也是如此。


The data that done() operates on is part of the coroutine frame and therefore when the handle becomes dangling, done() is also no longer functional. Instead done() only indicates whether the coroutine has reached its final suspension point, that is, it is currently suspended on the awaitable returned by final_suspend. If, as in your case, final_suspend does not trigger a suspension, the coroutine frame destroys itself and the coroutine_handle becomes dangling and must no longer be used.

Done()操作的数据是协程框架的一部分,因此当句柄变得悬空时,Done()也不再起作用。而Done()只指示协程是否已达到其最终挂起点,也就是说,它当前在由FINAL_SUSPEND返回的可等待挂起上挂起。如果与您的情况一样,finalSuspend没有触发挂起,则协程框架将自行销毁,并且协程句柄将变为悬挂状态,不能再使用。


Then, you may ask, why does this design allow a coroutine to destroy itself in the first place? This is indeed a peculiar design choice. In most cases, it is just not useful and your rule of thumb should be to always suspend_always on the final_suspend. In very rare cases, you may end up with a design where the coroutine is supposed to destroy itself and where the surrounding system logic ensures that it will not be accessed anymore afterwards. But this is a highly specialized and rather advanced use case, so I would not worry about it at all when learning the feature.

然后,你可能会问,为什么这个设计一开始就允许协程自我摧毁?这确实是一个奇特的设计选择。在大多数情况下,它是没有用的,您的经验法则应该是始终在最后一次挂起时挂起。在极少数情况下,您可能会得到这样一种设计:协程应该自行销毁,并且周围的系统逻辑确保以后不会再访问它。但这是一个高度专业化和相当高级的用例,所以我在学习该功能时根本不会担心它。


更多回答

"why does this design allow a coroutine to destroy itself in the first place?" This is common for non-generator coroutines that produce a single result. When the coroutine finishes, it stores the result in the return object and then destroys itself (since the coroutine is no longer needed - it finished its job, namely, to produce a result and store it in the return object).

“为什么这个设计一开始就允许协程器自我毁灭呢?”这对于生成单个结果的非生成器协程来说很常见。当协程结束时,它将结果存储在返回对象中,然后销毁自身(因为不再需要协程-它完成了它的工作,即产生一个结果并将其存储在返回对象中)。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com