• C++异步编程 for VS2011


    任务组:

    在之前我们介绍的异步操作都是基于Task<>的,这个是被封装好的类,可以作为传入,或者传出参数。下面我们要介绍的任务组的概念,他是比Task<>更轻量级的异步调用方式。

    在PPL中Concurrency::task_group和Concurrency::structured_task_group,这两个类都是异步操作的任务组,Concurrency::task_handle类是任务组的基本单位。

    我们先用 Concurrency::structured_task_group举例,我们通过structured_task_group::run 去添加任务,这个任务就是 Concurrency::task_handle,他的构造函数参数可以是函数指针,结构体重载()操作符,或者是lambda表达式。我们通过structured_task_group::wait去执行已经添加的任务,或者通过structured_task_group::run_and_wait去添加并执行所有的任务

    #include "stdafx.h"
    #include <ppl.h>
    #include <iostream>
    #include <functional>
    using namespace Concurrency;
    using namespace std;

    const struct functionstruct{
        void operator ()() const
        {
            cout<<"This is override struct operator "<<endl;
        }
    }myfunction;

    void taskfuncton ()
    {
        cout<<"This is function point"<<endl;
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
        // Function point
        auto task1=make_task(&taskfuncton);
        // Struct with () operator
        auto task2 = make_task(myfunction);
        // Lambda express
        auto task3 = make_task([] { cout<<"This is lambed express"<<endl; });

        // Create a structured task group and run the tasks concurrently.

        structured_task_group tasks;

        tasks.run(task1);
        tasks.run(task2);
        tasks.run_and_wait(task3);
        return 0;

    这里要注意一点的就是,这里的task都必须是没有返回值和传入参数的函数,或者lambda表达式。这就是和基于task<>最大的不同,基于task<>的任务组需要用when_all或者when_any来调度,我们可以获得到task<>的返回值,而structured_task_group不允许函数有传入和传出参数。

    我们也可以创建一个数状的任务组,如下图 

     

    对应的代码是

    // task-tree.cpp
    // compile with: /c /EHsc
    #include <ppl.h>
    #include <sstream>
    #include <iostream>
    #include <sstream>

    using namespace Concurrency;
    using namespace std;

    void create_task_tree()
    {   
       // Create a task group that serves as the root of the tree.
       structured_task_group tg1;

       // Create a task that contains a nested task group.
       auto t1 = make_task([&] {
          structured_task_group tg2;

          // Create a child task.
          auto t4 = make_task([&] {
             // TODO: Perform work here.
          });

          // Create a child task.
          auto t5 = make_task([&] {
             // TODO: Perform work here.
          });

          // Run the child tasks and wait for them to finish.
          tg2.run(t4);
          tg2.run(t5);
          tg2.wait();
       });

       // Create a child task.
       auto t2 = make_task([&] {
          // TODO: Perform work here.
       });

       // Create a child task.
       auto t3 = make_task([&] {
          // TODO: Perform work here.
       });

       // Run the child tasks and wait for them to finish.
       tg1.run(t1);
       tg1.run(t2);
       tg1.run(t3);
       tg1.wait();   

     我们可以通过structured_task_group::cancel 在内部或者外部来取消整个任务组,通过structured_task_group::is_canceling 来得到取消状态。

    对于异常我们要在.wait()方法外面加try_catch

    structured_task_group tg2;

    // Create a child task.      
    auto t4 = make_task([&] {
       // Perform work in a loop.
       for (int i = 0; i < 1000; ++i)
       {
          // Call a function to perform work.
          
    // If the work function fails, throw an exception to 
          
    // cancel the parent task.
          bool succeeded = work(i);
          if (!succeeded)
          {
             throw exception("The task failed");
          }
       }         
    });

    // Create a child task.
    auto t5 = make_task([&] {
       // TODO: Perform work here.
    });

    // Run the child tasks.
    tg2.run(t4);
    tg2.run(t5);

    // Wait for the tasks to finish. The runtime marshals any exception
    // that occurs to the call to wait.
    try
    {
       tg2.wait();
    }
    catch (const exception& e)
    {
       wcout << e.what() << endl;

    }

    上面说完了  Concurrency::structured_task_group,Concurrency::task_group 的使用方法基本上和前者类似。但是后者比前者更灵活,同样消耗的资源也更多。

    下面是他们两个之间不同的地方。 

    1. task_group是线程安全的,可以在别的线程里面通过run添加task, structured_task_group不允许多线程操作,而且所有的操作必须写在一个线程代码块里。

    2.  task_group可以再wait()方法执行之后,再通过run 方法添加task,而structured_task_group是固定的,.wait()后不能再添加。

    3. structured_task_group 建立的任务组树,子节点必须在父节点里面调用wait()的方法,因为structured_task_group只能在一个线程代码块里面执行,所以子节点必须要调用wait(),而task_group不需要。

    4.task_group 添加任务不需要调用make_task()方法, structured_task_group 必须调用。

        task_group tasks;

        tasks.run(&taskfuncton);
        tasks.run(myfunction);

        tasks.run_and_wait([] { cout<<"This is lambed express"<<endl; }); 

    总之, task_group较之structured_task_group又多封装了很多东西,如果没有特殊需要structured_task_group可以写出更高效的代码。

     引用自:

    http://msdn.microsoft.com/en-us/library/windows/apps/dd492427(v=vs.110).aspx 
    http://msdn.microsoft.com/en-us/library/windows/apps/dd984117(v=vs.110).aspx

    当前标签: Visual Studio 2011

     
    Jesse Jiang 2012-04-05 00:31 阅读:788 评论:0
     
    Jesse Jiang 2012-03-25 16:30 阅读:1168 评论:0
     
    Jesse Jiang 2012-03-18 16:17 阅读:999 评论:4
  • 相关阅读:
    跑mmaction代码遇到的问题:KeyError: 'xxxDataset is not in the dataset registry' when test #3751
    内存 显存 缓存
    fvcore计算模型参数量和计算量
    深度学习中模型参数量和计算量的理解与计算
    linux安装tmux
    findDecoder imread_(...) can't open/read file: check file path/integrity
    self._traceback = tf_stack.extract_stack()
    VRChat制作世界需要的unity包
    onnxruntime、cuda、cudnn、显卡驱动
    耗时统计
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2433751.html
Copyright © 2020-2023  润新知