根据这个最新的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模式.请随时提供反馈.
使用时构建以下代码
clang -Wall main.cpp -o main.o
Run Code Online (Sandbox Code Playgroud)
生成以下诊断(在代码之后):
template <typename F>
void fun(const F& f)
{
}
template <typename F>
void fun(F f)
{
}
double Test(double d) { return d; }
int main(int argc, const char * argv[])
{
fun(Test);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
诊断:
main.cpp:17:5: error: call to 'fun' is ambiguous
fun(Test);
^~~
main.cpp:2:6: note: candidate function [with F = double (double)]
void fun(const F& f)
^
main.cpp:8:6: note: candidate function [with F = double (*)(double)]
void fun(F f)
^ …Run Code Online (Sandbox Code Playgroud) 我觉得防止std::reference_wrapper<T>默认构造使得它更难使用,即使使用默认构造的reference_wrapper会导致运行时异常.
但是,a reference_wrapper是完全可复制的,因此它的值总是可以更改,那么为什么要阻止它默认使用 null引用呢?它使许多使用案例变得更加简单,使用它,observer_ptr不再需要提议- 为什么需要冗余?默认的可构造性reference_wrapper将统治它们!
思考?
随着C++ 11的出现,我们有unordered_map.cbegin/cend来专门返回const_iterator的值.所以在表达式"auto it = unordered_map.cbegin()"中推导出的'it'类型是const_iterator.
但是,当谈到unordered_map.find(key)函数时,我认为可能缺少一个"cfind()"对应物,它特意返回一个const_iterator.
有人说我们可以使用"const auto it = unordered_map.find(key)"来获取"const迭代器",但我强烈怀疑"const iterator"是相同的"const_iterator",其中"const iterator"的限制改变迭代器本身的能力,而"const_iterator"限制了改变迭代器引用的内容的能力.
所以,真的,如果我们想充分利用"自动"类型演绎(了解混淆或"自动"类型演绎的变化 - auto,auto&,const auto等),我怎么能有unordered_map .find(key)返回一个"const_iterator"而不必我明确指定"const_iterator" - 这就是auto的所有最佳用例之后!
下面是一个演示编译器行为的简单示例代码:
#include "stdafx.h"
#include <unordered_map>
int _tmain(int argc, _TCHAR* argv[])
{
typedef std::unordered_map<int, int> umiit;
umiit umii;
auto it0 = umii.find(0);
it0->second = 42;
const auto it1 = umii.find(0);
it1->second = 42;
umiit::const_iterator it2 = umii.find(0);
it2->second = 42; // expected compiler error: assigning to const
return 0;
}
Run Code Online (Sandbox Code Playgroud) 似乎以下 Redis Lua 脚本返回false而不是nil,这与文档所说的相矛盾:
> eval "local r = redis.call('get', 'none'); if r==nil then return 42 end" 0
(nil)
> eval "local r = redis.call('get', 'none'); if r==false then return 42 end" 0
(integer) 42
> eval "local r = redis.call('get', 'none'); if not r then return 42 end" 0
(integer) 42
Run Code Online (Sandbox Code Playgroud)
第一个eval在条件下失败r==nil,第二个eval似乎证明返回值是false
似乎 usingnot r是我手头最安全的选项,但此处的文档说该GET命令将返回nil
这是其他人都观察到并依赖的事实,即检查返回的命令的最安全的 Redis Lua 脚本nil是使用 …
似乎GetAwaiter可以等待任何实现需求的对象,Task<>类型只是满足此要求的众多可能类型之一.但是,似乎一种async方法只能返回Task<>或void据我所知.是否有可能挂钩我的自定义任务等待类型,所以我可以指定我的自定义等待类型作为异步返回类型,然后当然我可以随后await链接通常的调用链.像:(伪代码)
async MyAwaitable MyAwaitableMethod()
{
await myAwaitable;
}
async Task MyTask()
{
await MyAwaitableMethod();
}
Run Code Online (Sandbox Code Playgroud)
背景信息:整个想法实际上源于C++ 1z/2x协程提案,它基本上具有相同的基本模型,但它允许更多控制来定义promise_type从协程返回嵌入的任何类型(因此的co_await).
[编辑]
除了答案中提供的链接之外,我还在以下链接中找到了更多信息,似乎确实有一些关于这个主题的热门讨论:
[EDIT2]
令人惊讶的是,在进一步挖掘之后,这实际上是C#7.0的一个预期功能:http://intellitect.com/generalized-async-return-types/