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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM