Dej*_*avu 12 c++ multithreading coroutine async-await c++-coroutine
根据这个最新的C++ TS:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4628.pdf,基于对C#async/await语言支持的理解,我是想知道什么是C++协同程序的"执行上下文"(从C#借来的术语)?
我在Visual C++ 2017 RC中的简单测试代码表明,协同程序似乎总是在线程池线程上执行,并且很少控制应用程序开发人员可以执行协同程序的线程上下文 - 例如,应用程序是否可以强制执行所有协同程序(用编译器生成的状态机代码)只在主线程上执行,而不涉及任何线程池线程?
在C#中,SynchronizationContext是一种指定"上下文"的方法,其中所有协程"一半"(编译器生成的状态机代码)将被发布并执行,如以下文章所示:https://blogs.msdn.microsoft.com/pfxteam/2012/01/20/await-synchronizationcontext-and-console-apps /,而Visual C++ 2017 RC中的当前协程实现似乎总是依赖于并发运行时,它默认执行生成的状态机代码线程池线程.是否有类似的同步上下文概念,用户应用程序可以使用它来将协同程序执行绑定到特定的线程?
另外,在Visual C++ 2017 RC中实现的协同程序的当前默认"调度程序"行为是什么?即1)如何准确指定等待条件?2)当满足等待条件时,谁调用暂停的协程的"下半部分"?
关于C#中任务调度的我(天真)猜测是C#"完全"通过任务继续"实现"等待条件 - 等待条件由TaskCompletionSource拥有的任务合成,并且任何需要等待的代码逻辑将被链接为继续因此,如果满足等待条件,例如,如果从低级网络处理程序接收到完整消息,则它执行TaskCompletionSource.SetValue,它将基础任务转换为已完成状态,从而有效地允许链式连续逻辑开始执行(将任务从先前创建的状态置于就绪状态/列表中) - 在C++协程中,我推测std :: future和std :: promise将被用作类似的机制(std :: future是任务,而std :: promise是TaskCompletionSource,用法也非常相似!) - C++协同调度程序(如果有的话)依赖于某种类似的机制来执行行为吗?
[编辑]:在做了一些进一步的研究后,我能够编写一个非常简单但非常强大的抽象代码,称为awaitable,支持单线程和协作式多任务处理,并具有一个简单的基于thread_local的调度程序,它可以在根协同程序的线程上执行协同程序开始了.代码可以在这个github repo中找到:https://github.com/llint/Awaitable
等待是可组合的,它在嵌套级别维护正确的调用排序,并且它具有原始的让步,定时等待和从其他地方设置就绪,并且可以从中导出非常复杂的使用模式(例如只有无限循环协程当某些事件发生时被唤醒),编程模型紧跟C#Task async/await模式.请随时提供反馈.
Dav*_*aim 11
相反!
C++协程是关于控制的.这里的关键是
void await_suspend(std::experimental::coroutine_handle<> handle)
功能.
evey co_await期待等待类型.简而言之,等待类型是提供这三个功能的类型:
bool await_ready() - 程序是否应该停止执行协程?void await_suspend(handle) - 程序会为您传递该协程帧的延续上下文.如果你激活句柄(例如,通过调用operator ()句柄提供 - 当前线程立即恢复协程).T await_resume()- 告诉线程恢复协程恢复协程时要做什么以及返回什么co_await.因此,当你调用co_await等待类型时,程序会询问是否应该暂停协程(如果await_ready返回false),如果是这样的话 - 你会得到一个协程句柄,你可以随意做任何你喜欢的事情.
例如,您可以将协程句柄传递给线程池.在这种情况下,线程池线程将恢复协程.
你可以将coroutine句柄传递给一个简单的std::thread- 你自己的创建线程将恢复协程.
您可以将协程句柄附加到派生类中,OVERLAPPED并在异步IO完成时恢复协同程序.
正如您所看到的 - 您可以通过管理传入的协程句柄来控制协程暂停和恢复的位置和时间await_suspend.没有"默认调度程序" - 你如何实现等待类型将决定协程如何被调度.
那么,VC++会发生什么?遗憾的是,std::future仍然没有then功能,所以你无法将协程句柄传递给一个std::future.如果你等待std::future- 程序将只打开一个新的线程.查看future标题给出的源代码:
template<class _Ty>
void await_suspend(future<_Ty>& _Fut,
experimental::coroutine_handle<> _ResumeCb)
{ // change to .then when future gets .then
thread _WaitingThread([&_Fut, _ResumeCb]{
_Fut.wait();
_ResumeCb();
});
_WaitingThread.detach();
}
Run Code Online (Sandbox Code Playgroud)
那么为什么你会看到一个win32线程池线程,如果协程是以常规方式启动的std::thread?那是因为它不是协程.std::async在幕后打电话给concurrency::create_task.a concurrency::task默认情况下在win32线程池下启动.毕竟,整个目的std::async是在另一个线程中启动callable.
| 归档时间: |
|
| 查看次数: |
2949 次 |
| 最近记录: |