请看我们的 Visual Studio 2019版本16.8预览版3发行说明 了解更多最新功能。
对于C++和MSVC中的协同程序来说,这是一段漫长的旅程。我们宣布了 早期预览 2013年的可恢复功能,随后 /await
开关和 初始C++标准化建议 2014年,至 提案修订 在2015中,并通过Visual Studio 2017和2019继续跟踪协程序TS(技术规范)的进展。2019,在CORDOTION中加入C++标准,我们现在高兴地宣布Visual Studio 2019版本16.8中C++ 20协同程序的功能完成。
标准与TS协同程序
最终通过标准化进程并成为C++ 20的一部分的协同程序不同于我们在MSVC的早期提案草案和实验协同程序支持。 /await
开关。这使我们在16.8中完成了coroutine语言支持的两个重要且相互矛盾的目标:
- 提供一个C++ 20协同程序的实现,严格遵循标准,允许用户编写和使用可移植代码。
- 确保实验性协同程序的现有用户可以轻松地升级到16.8,而无需更改代码。
随着提议的改变,我们尽可能地添加了新的支持,而不会破坏早期采用协同程序的现有代码。这当然不是标准的:它仍然接受所有旧的关键字、名称和签名,与目标1相反 /await
,例如如何构造promise对象。这可能会导致以前编译过的程序无法编译或在运行时表现不同。
标准模式-/std:c++latest
在使用编译器支持的版本模式比C++ 17更新时,支持C++ 20的协同程序,而不需要传统的TS支持。 /std:c++latest
并将继续进入编号版本开关后,C++ 17,因为这些都是添加。在使用这种语言开关编译时 /await
您可以在库中支持对C++ 20的协同程序的严格支持。 <coroutine>
标题并在中定义 std
命名空间。此模式将在早期方案的非标准代码上发出错误,例如裸代码 await
关键字或 initial_suspend
返回的函数 bool
,并且仅支持与早期实现不同的标准行为。
扩展模式–/await
coroutine的早期采用者可以继续使用 /await
开关和任何语言版本开关(包括 /std:c++latest
),并继续使用实验标头和命名空间。我们在这种模式下添加了缺失的标准特性和错误修复,只要它们不破坏兼容性。
我们建议现有的协同程序用户尽快转向标准的协同程序,新用户应该更喜欢标准模式 /await
. 支持 /await
切换将继续为现有用户,但未来的协同路由是在标准模式和新的功能将在那里实施。将项目从 /await
C++ 20是一个简单的过程。
16.8的新增功能
版本16.8在协同程序中引入了几个新特性和改进:
- 对称传输
- 无操作协同程序
- 协程承诺构造函数参数
- 定义良好的异常行为离开协同程序体
- 标准返回对象转换行为
- 改进的调试体验
- 通用框架布局,提高与其他供应商的兼容性
- 大量错误修复
这些更改中的大多数只有在标准模式下构建时才可用,尽管没有op协同程序,而且大多数bug修复也都是在标准模式下实现的 /await
. 在本文的其余部分中,我们将更详细地了解其中的一些项目,以及VisualStudio中的协同程序的下一步工作。
对称传输和无操作协程
这是C++ 20协同程序支持的最后两个大片段。使用对称传输,一个协程可以指示另一个协程的协程句柄,以便在挂起时立即恢复。这是通过定义 await_suspend
返回类型为的协程承诺函数 coroutine_handle<T>
:
struct some_awaitable { ... std::coroutine_handle<> await_suspend(std::coroutine_handle<promise_type> h) noexcept { // If the coroutine that is about to suspend (indicated by h) has a continuation // coroutine handle, resume that coroutine instead of returning to the caller. // Otherwise, return a no-op coroutine. The no-op coroutine does nothing, and will // allow control to return to the caller. return h.promise().continuation ? *continuation : std::noop_coroutine(); } };
在标准模式下,此挂起和恢复操作在调用堆栈中不引入其他帧的情况下工作。这允许在协程之间进行无限数量的传输,而不会冒堆栈溢出的风险。
改进的调试体验
版本16.8引入了几个新的调试特性来处理协同程序。一些关于进入和在协同过程中的问题已经解决了,特别是我的代码。现在还可以在协同过程中展开帧指针。这将公开诸如协程参数值和promise类型的成员之类的数据(仅限标准协程)。我们还更改了许多编译器生成的符号的名称,以便更好地处理调试器的表达式求值。现在,它们更易于在即时窗口或监视窗口中使用,或者用作条件断点。
公共框架布局
标准C++ 20模式中的协同程序框架有一个新的内部表示。这暴露了框架中对于使用协同程序非常重要的部分,例如如何恢复或销毁协同程序,这种方式在供应商中很常见。然后,在一个供应商生成的对象文件或库中生成的协程可能会被另一个供应商使用。这并不意味着全框架布局在供应商之间是通用的,甚至不能保证在编译器版本之间是稳定的,但是它确实标准化了(尽管是非正式的)标准库类型之间的接口 std::coroutine_handle
以及底层的协程框架对象,并且在公开或使用库中的协程时应该有助于提高兼容性和灵活性。我们还引入了对Clang使用的相同内置函数的支持,允许更好的头级兼容性。
不同供应商之间的协同程序支持水平目前各不相同,但正在提高。由于C++ 20支持广泛地跨编译器,所以我们希望这变得更加有用和重要。我们致力于为协同程序提供一个通用的、稳定的ABI,以使不同构建之间的接口尽可能无缝。
下一步是什么?
C++ 20中的Coroutines有点有限。已经采用了核心语言特性,但是在标准库中没有真正的协同程序支持。好消息是,我们期待不久会发生变化,在下一个C++语言版本中,对支持程序的更广泛的库支持。
我们接下来的C++ 20协同程序的步骤是不断改进调试经验。其中一个方面是更自然的步进行为,这使得更容易跟踪协同程序的执行,就好像它是一个正常的同步函数一样。我们还研究了协同程序句柄的改进的可视化,以方便地查看挂起的协同程序的状态。
一如既往,欢迎对此功能进行反馈,并可以在上生成错误报告 开发者社区 . 恭候佳音!