如何在循环中使用ppl任务和.then?

时间:2016-01-19 13:27:50

标签: c++ concurrency ppl

我正在努力学习ppl。而不是使用线程。让我们从头开始。我有这个简单的问题:

V1:

            while(true)
            {
                auto important_msg = ReceiveImportantMessage_Blocking(); //Blocks for about 20s until there is a new message
                //do processing on important_msg
                auto unimportant_msg = ReceiveUnimportantMessage_Blocking(); //Blocks for about 60s until there is a new message
                //do processing on unimportant_msg
            }

v1显然很糟糕,因为这两个调用都会阻塞并最终等待彼此。

V2:

            while(true)
            {
                auto important_msg = ReceiveImportantMessage_Blocking(); //Blocks for about 20s until there is a new message
                //do processing on important_msg
                auto unimportant_msg = CheckForUnimportantMessage_NonBlocking(); //works by polling queue. Returns empty if no message
                if(unimportant_msg) {
                    //do processing on unimportant_msg
                }
            }

v2更好,因为不重要的消息不会阻止重要消息。此外,重要消息在收到后会被处理。在我们收到重要消息之前,这些不重要的消息虽然没有得到检查。因此,当我到达它时,不重要的消息可能是20岁。

V3:

            while(true)
            {
                auto important_msg = CheckForImportantMessage_NonBlocking(); //works by polling queue. Returns empty if no message
                if(important_msg) {
                    //do processing on important_msg
                }   
                auto unimportant_msg = CheckForUnimportantMessage_NonBlocking(); //works by polling queue. Returns empty if no message
                if(unimportant_msg) {
                    //do processing on unimportant_msg
                }
                sleep(10); //just so we don't busy wait.    
            }

v3更快地获得不重要的消息。但它对重要消息的速度也较慢。重要消息的处理一旦收到就不会发生。但只有当我到处检查它时。当我添加一个睡眠以避免繁忙等待(并且消耗太多的CPU时间)时,重要的消息将比v2需要更长的时间来接收和处理。

V4:

            {
                auto important_msg_task = ReceiveImportantMessageTask_NonBlocking(); //ppl::task
                auto unimportant_msg_task = ReceiveUnimportantMessageTask_NonBlocking(); //ppl::task
                while(true)
                {
                    if(important_msg_task.is_done()) {
                        auto important_msg = important_msg_task.get();
                        //do processing on important_msg
                        important_msg_task = ReceiveImportantMessageTask_NonBlocking(); //listen for new message
                    }
                    if(unimportant_msg_task.is_done()) {
                        auto unimportant_msg = unimportant_msg_task.get();
                        //do processing on important_msg
                        unimportant_msg_task = ReceiveUnimportantMessageTask_NonBlocking(); //listen for new message
                    }
                    sleep(10); //just so we don't busy wait.    
                }
            }

V4与v3相同。只是用ppl任务代替。它的问题是一旦接收到重要消息就不会处理。

V5) 我想要删除睡眠并使用important_msg_task"。然后"一旦收到处理就开始处理,然后"。然后"处理旧邮件后,请收听新邮件,然后" .then"处理新消息等(并对unimportant_msg_task执行相同操作)。我不知道如何在循环中完成这项工作。看来我最终将永远不断增加一系列连接任务。

那么如何使用ppl解决这个问题(或者至少没有原始​​线程)?

1 个答案:

答案 0 :(得分:0)

使用这种惯用代码:

template<typename Func>
concurrency::task<void> doWhile(Func func)
{
  static_assert(
    std::is_same_v<decltype(func()), bool> ||
    std::is_same_v<decltype(func()), concurrency::task<bool>>);

  return concurrency::create_task(func)

    .then([func](bool needToContinue)
    {
      if (needToContinue)
        return doWhile(func);

      return concurrency::task_from_result();
    });
}

对于一个任务,您可以编写如下内容:

concurrency::task<bool> process() {
  // launching initial task
  auto important_msg_task = ReceiveImportantMessageTask_NonBlocking(); //ppl::task

  // adding continuation with processing of the result
  auto continuation = important_msg_task.then([](const Message &msg)
  {
    // do processing on important msg

    // decide whether to continue or stop processing
    return stopProcessing() ? false : true;
  });

  return continuation;
}

auto loop = doWhile([] {
  return process();
});

使用loop.get()等到处理完成。

要有两个并行处理的“循环”,只需为另一个“循环”触发第二个doWhile,例如像这样:

auto loop2 = doWhile([] {
  return ReceiveUnimportantMessageTask_NonBlocking()
    .then([](const Message &msg)
    {
      //do processing on unimportant msg
      return !stopProcessing();
    });
});

由于所有任务都在线程池上执行,因此具有多个doWhile可以有效地使处理并行化。