看完Gor Nishanov对await和coroutines 的采访后,我决定玩一些可恢复的功能N4131.然后我意识到以下代码在我的第二个问题上打印了'false'(使用Visual Studio 2015 RC和在线编译器测试(需要标志:) /await):
#include <future>
#include <iostream>
using namespace std;
using namespace chrono;
struct Foo
{
future<void> coro(thread::id ui_thread_id)
{
cout << "Q: awaiting result in UI thread? " << boolalpha << (this_thread::get_id() == ui_thread_id) << endl;
auto intermediate_result = __await async([] {
this_thread::sleep_for(250ms);
return 42;
});
cout << "Q: received result in UI thread? " << boolalpha << (this_thread::get_id() == ui_thread_id) << endl;
result = intermediate_result; // race
}
int result = 0;
};
int main()
{
const auto ui_thread_id = this_thread::get_id();
Foo f;
auto c = f.coro(ui_thread_id);
for (int i = 0; i < 7; ++i)
{
cout << " -- event loop: " << f.result << endl;
this_thread::sleep_for(50ms);
}
c.wait();
}
Run Code Online (Sandbox Code Playgroud)
我的期望是由于"调用者无法观察到函数作为可恢复函数实现的事实"(N4131,第8页,可恢复函数,第4段).
这似乎是一个重要的细节,我在N4131中找不到任何澄清我的问题的陈述.
期望可恢复功能在原始线程中恢复工作是不对的?如果是错的,请尝试解释原因?
回答你的问题:是的,期望可恢复函数实际上在原始线程中恢复工作可能是错误的,因为该提案未明确说明该行为(也许是故意的,也许不是)。
我认为你的误解是围绕示例中哪个函数是可恢复的,因此哪个函数受到“调用者无法观察到函数被实现为可恢复函数这一事实”的约束。
来自提案(强调我的):
如果函数或 lambda 的主体包含至少一个挂起/恢复点,则该函数或 lambda 称为可恢复函数或可恢复 lambda称为可恢复函数或可恢复 lambda 。挂起/恢复点是带有一个或多个await 运算符、yield 语句或await-for 语句的表达式
这意味着 lambda 不是可恢复函数,coro因为await关键字是其主体的一部分。该提案指定了可恢复函数对其调用者的行为方式,并且该示例表明调用者确实无法观察到它,main()在这种情况下,无论它是否实现为可恢复(main()返回时仍然在 UI 线程上coro)。
现在,有人可能会说,这可能是提案中的一个疏忽,没有具体说明这一点,但我确信这样做是有充分理由的,但我无法在提案中找到与实际恢复相关的任何内容。功能。
关于与可修改参数的交互也可能存在争议。例如:
future<void> coro(thread::id ui_thread_id, int* foo)
{
auto intermediate_result = __await async([] {
this_thread::sleep_for(250ms);
});
*foo = 42;
}
Run Code Online (Sandbox Code Playgroud)
我个人会考虑这样一个事实foo,但有人可能会反驳(我不是最擅长标准语言)。
最后但并非最不重要的一点是,我不确定您对结果分配的看法是否异常种族化。它确实与读入竞争,main()但您专门为此编写了代码,并且只有一个赋值(函数体在调用时暂停await,并在异步 lambda 返回后恢复)。改变await为在同一线程上恢复根本不会影响这种情况(除非在非原子读写的情况下,您可以读取处于不一致状态的对象,这是另一种蠕虫病毒,并且可能是一个有效点) 。
请注意,此功能还很年轻,目前仅在 MSVC IIRC 中进行实验性实现,因此我希望它在标准化之前会经历一些更改(如果有的话)。还有一个不可忽视的可能性,这实际上是规范/实现错误。
话虽这么说,很有可能恢复可恢复功能的行为几乎没有被指定,以便在实现中提供更多自由。