c++ - 在评估内部等待表达式期间可以销毁协程吗?
问题描述
根据标准,协程只有在挂起时才会被销毁[dcl.fct.def.coroutine]
如果为未挂起的协程调用destroy,则程序具有未定义的行为。
在协程 A 内的await 表达式求值期间,假设此事件序列对应于[expr.await]/5.1:
- 协程 A 被挂起,因为await-ready为假;
- 在将控制权交给协程 A 调用者之前,协程 B 被恢复;
- 一旦 B 也被挂起,控制流将返回给协程 A 调用者。
协程 A 可以在协程 B 恢复后挂起之前销毁吗?
示例代码:
#include <coroutine>
using namespace std;
struct task
{
struct promise_type;
using handle_type = coroutine_handle<promise_type>;
struct promise_type
{
handle_type resumer = nullptr;
auto
get_return_object(){
return task{handle_type::from_promise(*this)};
}
auto
initial_suspend(){
return suspend_always {};
}
auto
unhandled_exception(){}
auto
final_suspend(){
return suspend_always{};
}
void
return_void() {}
};
handle_type handle;
void await_resume(){
handle.resume();
}
auto
await_suspend(handle_type h){
handle.promise().resumer = h;
return handle;
}
auto
await_ready(){
return false;
}
};
int main(){
task coroutine_B = [&coroutine_B]() ->task
{
coroutine_B.handle.promise().resumer.destroy();
co_return;
}();//coroutine B supended at initial suspend
task coroutine_A = [&coroutine_B]() ->task
{
co_await coroutine_B;//set coroutine_B resumer to coroutine_A handle
//then resume coroutine_B.
}();//coroutine A supended at initial suspend.
coroutine_A.handle.resume();//execute co_await coroutine_B;
//is this UB?
}
从这里可以看出,代码可以编译并且运行起来似乎没有任何问题。
另一方面,这个显然等效的版本在这里崩溃。
解决方案
协程状态在以下情况下被破坏......
destroy
引用协程的协程句柄的成员函数被调用......如果destroy
为未挂起的协程调用,则程序具有未定义的行为。
在您的示例中,是为 的协程句柄destroy
调用的,该句柄由于. 所以成员函数是为一个挂起的协程调用的,所以其中没有未定义的行为。coroutine_B
coroutine_A
co_await
destroy
事实上,Clang、GCC、MSVC 都可以很好地编译和执行代码:https ://gcc.godbolt.org/z/zxePvsvx1
另一方面,这个显然等效的版本在这里崩溃。
这里的问题是在 GCC中coroutine_B.resumer
包含地址,所以是未定义的行为。演示:https ://gcc.godbolt.org/z/T8aa45ez1nullptr
coroutine_B.resumer.destroy()
推荐阅读
- swift - 在 Swift 中从 Firebase 身份验证中删除用户
- reactjs - 使用redux-form按下下一个键盘按钮后如何使用useRef钩子选择下一个TextInput
- mysql - 无法从 Spring Boot Docker 容器连接到本地 MySQL 数据库服务器
- java - 如何唯一存储 docx 或 pdf 文件并在 oracle db 中检索它
- unix - 是否可以暂停在屏幕下运行的命令?
- python - 如何切换字符串中的文本?
- kubernetes - Kubernetes 隐藏每个节点限制 110 个 pod?
- c - 合并排序的更好方法是什么?递归函数还是非递归?
- android - 如何设置将在我想要为 id 执行的表单上预填的值
- react-native - 如何在 Mapview 中显示 GPS 坐标?