【问题标题】:How to return value from nested task in c++/cx?如何从 c++/cx 中的嵌套任务返回值?
【发布时间】:2016-01-24 05:25:21
【问题描述】:

我有一堆类似这样的线程任务:

create_task(somewinrtasyncfunction()).then([this(variable_that_the_last_task_returned)
{
    //task here
    return info;
}).then([this](info)
{
    //another task here
    return status});

现在我想在任务之外,在调用它的函数中使用status。我将如何访问它?

【问题讨论】:

    标签: c++ multithreading visual-c++ win-universal-app c++-cx


    【解决方案1】:

    你returncreate_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&lt;int&gt; 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.
    

    【讨论】:

      猜你喜欢
      • 2013-10-26
      • 1970-01-01
      • 2014-09-02
      • 2021-10-02
      • 1970-01-01
      • 1970-01-01
      • 2016-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多