如何从 c++/cx 中的嵌套任务中获取 return 值?
How to return value from nested task in c++/cx?
我有一堆这样的线程任务:
create_task(somewinrtasyncfunction()).then([this(variable_that_the_last_task_returned)
{
//task here
return info;
}).then([this](info)
{
//another task here
return status});
现在我想在任务之外,在调用它的函数中使用 status
。我将如何访问它?
您 return
由 create_task(...).then(...).then(...)
创建的任务(或值)。
如果您需要同步获取结果,您可以尝试在task
上调用.get()
,但是那将不 在应用程序的主 UI 线程上工作,这不是你应该做的事情。代码 可能 今天在后台线程上运行,但您将来可能最终会在 UI 线程上调用该函数——也许是通过某种非常迂回的方式—— - 然后你的应用程序就会崩溃。修复该应用程序的唯一方法是将您的代码重新设计为异步的......就像它应该放在首位一样。
此外,请注意,尝试自行解决以同步获取值(例如在任务中发出信号的对象上调用 WaitForSingleObjectEx()
)可能会使许多 WinRT 的 UI 线程死锁异步方法。 不要这样做!
您应该继续异步链以对值进行操作。这是一个简单的例子;从您的 UI 主线程调用 test()
。
concurrency::task<int> get_double_async(int value)
{
return concurrency::create_task(
[value]()
{
return value * 2;
});
}
// DON'T DO THIS - IT IS A BUG FARM WAITING TO HAPPEN!
int try_calling_get()
{
auto value = 2;
value = get_double_async(value).get(); // TODO: Don't do this!
value = get_double_async(value).get(); // TODO: Don't do this!
return value;
}
concurrency::task<int> do_it_properly()
{
auto value = 2;
return get_double_async(value).then([](int value)
{
return get_double_async(value).then([](int value)
{
return value;
});
});
}
void test()
{
wchar_t buff[255];
swprintf_s(buff, L"test() being called on thread %d.\r\n", GetCurrentThreadId());
OutputDebugString(buff);
// this will fail at runtime if called from UI thread
try
{
auto x = try_calling_get();
}
catch (const concurrency::invalid_operation& op)
{
// "Illegal to wait on a task in a Windows Runtime STA"
swprintf_s(buff, L"try_calling_get() threw '%hs'; thread is %d.\r\n",
op.what(), GetCurrentThreadId());
OutputDebugString(buff);
}
// this will "work", but only because it is forced into a threadpool thread
concurrency::create_task([]
{
auto x = try_calling_get(); // TODO: Don't do this!
wchar_t buff[255];
swprintf_s(buff, L"try_calling_get() returned %d; thread is %d.\r\n",
x, GetCurrentThreadId());
OutputDebugString(buff);
});
// this is the preferred way to do it
do_it_properly().then([](int x)
{
wchar_t buff[255];
swprintf_s(buff, L"do_it_properly() returned %d; thread is %d.\r\n",
x, GetCurrentThreadId());
OutputDebugString(buff);
});
}
请注意,此示例使用基于值的延续 .then([](int value){...})
而不是基于任务的延续 .then([](task<int> value){...})
;如果您想控制异常之类的事情,您可以使用基于任务的延续。
这里有一个示例运行(线程ID每次都会不同,有时最后两个相同)
test() being called on thread 3576.
First-chance exception at 0x77134598 in UniversalNativeApp.Windows.exe: Microsoft C++ exception: Concurrency::invalid_operation at memory location 0x038CEC94.
try_calling_get() threw 'Illegal to wait on a task in a Windows Runtime STA'; thread is 3576.
try_calling_get() returned 8; thread is 5972.
do_it_properly() returned 8; thread is 9976.
我有一堆这样的线程任务:
create_task(somewinrtasyncfunction()).then([this(variable_that_the_last_task_returned)
{
//task here
return info;
}).then([this](info)
{
//another task here
return status});
现在我想在任务之外,在调用它的函数中使用 status
。我将如何访问它?
您 return
由 create_task(...).then(...).then(...)
创建的任务(或值)。
如果您需要同步获取结果,您可以尝试在task
上调用.get()
,但是那将不 在应用程序的主 UI 线程上工作,这不是你应该做的事情。代码 可能 今天在后台线程上运行,但您将来可能最终会在 UI 线程上调用该函数——也许是通过某种非常迂回的方式—— - 然后你的应用程序就会崩溃。修复该应用程序的唯一方法是将您的代码重新设计为异步的......就像它应该放在首位一样。
此外,请注意,尝试自行解决以同步获取值(例如在任务中发出信号的对象上调用 WaitForSingleObjectEx()
)可能会使许多 WinRT 的 UI 线程死锁异步方法。 不要这样做!
您应该继续异步链以对值进行操作。这是一个简单的例子;从您的 UI 主线程调用 test()
。
concurrency::task<int> get_double_async(int value)
{
return concurrency::create_task(
[value]()
{
return value * 2;
});
}
// DON'T DO THIS - IT IS A BUG FARM WAITING TO HAPPEN!
int try_calling_get()
{
auto value = 2;
value = get_double_async(value).get(); // TODO: Don't do this!
value = get_double_async(value).get(); // TODO: Don't do this!
return value;
}
concurrency::task<int> do_it_properly()
{
auto value = 2;
return get_double_async(value).then([](int value)
{
return get_double_async(value).then([](int value)
{
return value;
});
});
}
void test()
{
wchar_t buff[255];
swprintf_s(buff, L"test() being called on thread %d.\r\n", GetCurrentThreadId());
OutputDebugString(buff);
// this will fail at runtime if called from UI thread
try
{
auto x = try_calling_get();
}
catch (const concurrency::invalid_operation& op)
{
// "Illegal to wait on a task in a Windows Runtime STA"
swprintf_s(buff, L"try_calling_get() threw '%hs'; thread is %d.\r\n",
op.what(), GetCurrentThreadId());
OutputDebugString(buff);
}
// this will "work", but only because it is forced into a threadpool thread
concurrency::create_task([]
{
auto x = try_calling_get(); // TODO: Don't do this!
wchar_t buff[255];
swprintf_s(buff, L"try_calling_get() returned %d; thread is %d.\r\n",
x, GetCurrentThreadId());
OutputDebugString(buff);
});
// this is the preferred way to do it
do_it_properly().then([](int x)
{
wchar_t buff[255];
swprintf_s(buff, L"do_it_properly() returned %d; thread is %d.\r\n",
x, GetCurrentThreadId());
OutputDebugString(buff);
});
}
请注意,此示例使用基于值的延续 .then([](int value){...})
而不是基于任务的延续 .then([](task<int> value){...})
;如果您想控制异常之类的事情,您可以使用基于任务的延续。
这里有一个示例运行(线程ID每次都会不同,有时最后两个相同)
test() being called on thread 3576.
First-chance exception at 0x77134598 in UniversalNativeApp.Windows.exe: Microsoft C++ exception: Concurrency::invalid_operation at memory location 0x038CEC94.
try_calling_get() threw 'Illegal to wait on a task in a Windows Runtime STA'; thread is 3576.
try_calling_get() returned 8; thread is 5972.
do_it_properly() returned 8; thread is 9976.