美文网首页
C++ REST SDK中的异步任务库PPLX

C++ REST SDK中的异步任务库PPLX

作者: 长不胖的Garfield | 来源:发表于2016-12-29 16:06 被阅读0次

    简介

    C++ REST SDK中提供了PPLX用来支持异步操作,姑且可以认为PPLX是微软PPL-并行模式库/并发运行时任务并行task部分。

    C++ REST SDK中,对于task的使用也是推荐开发者查阅并发运行时部分,在任务并行(并发运行时)可以对其进行了解。
    Programming with Tasks中描述了C++ REST SDK中对任务编程的基本信息。

    目标

    在以下内容中,将了解PPL的任务部分,也就是task的使用方法,由此了解异步操作如何实现:

    1. 任务的创建及运行
    2. 任务的合并
    3. 任务的取消
    4. 处理异常
    5. 其它

    任务的创建及运行

    task构造时,构造参数可以为可调用对象或者task_completion_event,譬如:

    //构造函数
    auto task = pplx::task<int>([](){
        return 10;
    });
     
    //lambda
    auto task = []()->pplx::task<int>{
        return pplx::task_from_result(10);
    };
     
    //create_task
    auto task = pplx::create_task([](){
        return 10;
    });
     
    //create_task的另一种方式
    pplx::task_completion_event<int> tce;
    auto task = pplx::create_task(tce);
    

    添加延续任务使用task.then形成异步工作链:

    auto s = std::make_shared<std::string>("Value 1");
     
    return pplx::create_task([s]{
        std::cout <<"Current Valus:" << *s << std::endl;
        *s = "Value 2";
        //异步任务1
    }).then([s]{
     
        std::cout << "Current Valus:" << *s << std::endl;
        *s = "Value 3";
        return *s;
        //异步任务2
    }).then(异步任务3)....
    

    上述示例会依次输出Value 1,Value2,Value3...

    使用task.get或者task.wait执行异步任务:

    • get
      阻塞直到任务执行完成,并返回任务结果,当任务取消时,抛出task_canceled异常,发生其它异常也会被抛出;
    • wait
      等待任务到达终止状态,然后返回任务状态:completed、canceled,如果发生异常会被抛出。

    任务的合并

    when_all 或者 &&

    返回合并任务,只有当所有任务都完成时合并任务才会返回成功;如果任何一个任务被取消或者抛出异常,则合并任务会完成并处理取消状态,在合并任务get或者wait时抛出异常,示例如下:

    std::array<pplx::task<void>, 3> tasks = {
        pplx::create_task([] { std::cout << "Hello from taskA." << std::endl; }),
        pplx::create_task([] { std::cout << "Hello from taskB." << std::endl; }),
        pplx::create_task([] { std::cout << "Hello from taskC." << std::endl; })
    };
     
    auto joinTask = pplx::when_all(std::begin(tasks),std::end(tasks));
     
    std::cout<<"Hello from the joining thread."<<std::endl;
    joinTask.wait();//等待任务完成
    

    如果任务类型为task<T>,则合并任务类型为task<vector<T>>

    when_any 或者 ||

    返回合并任务,当任何任务完成时合并任务就会返回成功;如果所有任务都被取消或者抛出异常,则合并任务会完成并处理取消状态,并且如果任何任务发生异常,在合并任务get或者wait时抛出异常。

    合并任务返回类型为task<size_t>,即返回完成任务的索引。

    任务的取消

    pplx::cancellation_token_source中包裹了cancellation_token,用来提供取消操作,通过cancellation_token.is_canceled()在执行任务的过程中判断任务是否要被取消:

    pplx::cancellation_token_source cts;
    std::cout<<"Creating task..."<<std::endl;
     
    auto task = pplx::create_task([cts]{
        bool moreToDo = true;
        while (moreToDo)
        {
           if (cts.get_token().is_canceled())//判定是否被取消了
           {
               return;
           }
           else
           {
               moreToDo = []()->bool {
                   std::cout << "Performing work..." << std::endl;
                   pplx::wait(250);
                   return true;
               }();
           }
        }
    });
     
     
    pplx::wait(1000);
     
    std::cout<<"Canceling task..."<<std::endl;
    cts.cancel();
    std::cout<<"Waiting for task to complete..." <<std::endl;
    task.wait();
    std::cout<<"Done."<<std::endl;
    

    注意cancellation_token_source要使用传值操作,其类似于智能指针。

    当要在异步工作链中支持取消时,需要将cancellation_token作为构造task的参数传递,然后结合task.wait判断是否要取消:

    pplx::cancellation_token_source cts;
    auto task = pplx::task<void>([cts](){
     
        std::cout<<"Cancel continue_task"<<std::endl;
        cts.cancel();
    }).then([](){
        std::cout<<"this will not run"<<std::endl;
    },cts.get_token());
     
    try
    {
        if (task.wait() == pplx::task_status::canceled)
        {
            std::cout<<"taks has been canceled"<<std::endl;
        }
        else
        {
            task.get();
        }
    }
    catch (const std::exception& e)
    {
        std::cout <<"exception: "<<e.what()<<std::endl;
    }
    

    处理异常

    之前说过如果任务发生异常,会在get或者wait时抛出,但是如果希望在异步任务链中判定之前执行是否发生异常做出操作时,可以采用另外的方式。

    当使用task.then时一般是这样写的:

    task<T>.then([](T t){
         //处理任务结果t
    })
    

    这时候进入then时之前的任务已经执行完成了,task.then有另外一种写法,能够在then时并没有执行任务:

    task<T>.then([](task<T> task){
           try 
           {
                  task.get(); //使用get或者wait执行任务
           }
           catch(...)
           {
               //处理异常
           }
    })
    
    

    其它

    • task_from_result
      从结果直接构造task,用来不再继续执行,返回task<TResult>结果
    • task_from_execption
      从异常构造task
    • task_options
      task创建选项,用来指定task的调度器、取消标志等内容

    总结

    pplx为我们提供了基于任务的编程模型,为异步编程提供了相对简单的实现方法,后续在C++ REST SDK使用中可以看到其应用。

    相关文章

      网友评论

          本文标题:C++ REST SDK中的异步任务库PPLX

          本文链接:https://www.haomeiwen.com/subject/kwguvttx.html