C ++ 1z协程线程上下文和协程调度

根据最新的C ++ TS:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4628.pdf,基于对C#异步/等待语言支持的理解,我想知道什么是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仓库中找到:https://github.com/llint/Awaitable

Awaitable组合的方式是它可以在嵌套级别维护正确的调用顺序,并且它具有原始的产生式,定时等待以及从其他位置准备就绪的特性,并且可以从中派生出非常复杂的使用模式(例如无限循环协程在某些事件发生时醒来),编程模型紧跟C#Task基于异步/等待模式。 请随时提供您的反馈。


相反!

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
  • 所以当你在等待类型上调用co_await时,如果协程被暂停(如果await_ready返回false),程序会询问等待状态,如果是这样 - 你会得到一个协程句柄,你可以在其中执行任何你喜欢的操作。

    例如,您可以将协程句柄传递给线程池。 在这种情况下,线程池线程将恢复协程。

    您可以将协程句柄传递给一个简单的std::thread - 您自己的创建线程将恢复协程。

    您可以将协程句柄附加到派生类OVERLAPPED并在异步IO完成时恢复协程。

    正如你所看到的 - 你可以通过管理在await_suspend传递的协程句柄来控制协程暂停和恢复的位置和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();
        } 
    

    那么,为什么你看到一个win32线程池线程,如果协程是在一个普通的std::thread呢? 那是因为它不是协程。 std::async在幕后调用concurrency::create_task 。 一个concurrency::task默认在win32 concurrency::task池下启动。 毕竟, std::async的全部目的是在另一个线程中启动可调用。

    链接地址: http://www.djcxy.com/p/53205.html

    上一篇: C++1z coroutine threading context and coroutine scheduling

    下一篇: based state machine (FSM): Passing in events