VS2010点滴——Concurrency Runtime namespace(异步编程一)

微软已经在VS10中加入了Concurrency Runtime namespace来支持C++的异步编程,笔者认为异步编程在是现代编程语言的一个发展方向。在此总结一些异步编程的基本概念和语法,希望能给大家理解异步编程带来一些方便。

首先,异步编程的基本单位是task class。我们把想要执行异步操作的函数放入task 里面,通过协调这些task的关系,来实现基于函数的异步操作。这种方式相对于传统的基于线程池的异步调用,开发者不需要关心底层的线程如何分配,资源如何同步,是否有死锁的存在。这样,开发者会更专注于代码的逻辑,进而提高编程的效率。

task<T> 是一个模板类,T是函数返回值的类型,比如task<int> t([](){return 1;}),或者函数返回值为空task<void> t([](){return;})。task的构造函数传入参数可以是lambda表达式。我们声明了一个task之后,通过调用wait()方法去执行他,对于有返回值的task,我们调用.get()方法去取得他的返回值。下面是一个简单的例子

  1. #include <ppltasks.h>  
  2. #include <iostream>  
  3. using namespace Concurrency;  
  4. using namespace std;  
  5. int wmain()  
  6. {  
  7.     task<int> t([]() {  
  8.         return 42;  
  9.     });  
  10.  
  11.     t.wait();  
  12.     wcout << t.get() << endl;  

我们可以用.then()的方法去指定一个连续的任务,就是在前一个task完成之后立刻执行.then()里面的函数。这个函数要求接受前一个任务返回的结果。比如前一个任务中函数返回的是int 那么在.then()的函数里面就要指定传入参数为int的lambda表达式()[int res]{ res++;}。.then()方法只要求传入参数和上一个任务相同,而返回值可以不同。比如下面的代码,第一个task返回int,在第一个then中返回void,然后返回int,最后返回void。这里要注意的是,在最后一个then()中调用wait,而不是t.wait(),否则第一个.then 不会执行。

  1. task<int> t([]() {  
  2.     return 42;  
  3. });  
  4.  
  5. t.then([](int res){wcout<<"Hello";}).then([](){return 1;}).then([](int res){wcout<<res<<endl;}).wait();  
  6. wcout << t.get() << endl; 

这段代码展示的是如何嵌套task,注意这里的返回值虽然是task<int>,但是外面的task的参数依然是int,这两个参数要保持一致。

  1. task<int> t([]() {   
  2.     wcout << L"Task A" << endl;  
  3.  
  4.     // Create an inner task that runs before any continuation  
  5.     // of the outer task.  
  6.     return task<int>([]() {  
  7.         wcout << L"Task B" << endl;  
  8.         return 1;  
  9.     });  
  10. }); 

一组task的执行,我们可以把一组task放入到容器里,然后通过when_all(),这个函数去执行他们,when_all传入参数是容器迭代器的开始和结束。这里要求容器里面的task的返回值必须相同。这是没有返回值的例子

  1.  // Start multiple tasks.  
  2. array<task<void>, 3> tasks = {  
  3.     task<void>([] { wcout << "Hello from taskA." << endl; }),  
  4.     task<void>([] { wcout << "Hello from taskB." << endl; }),  
  5.     task<void>([] { wcout << "Hello from taskC." << endl; })  
  6. };  
  7. auto joinTask = when_all(tasks.begin(), tasks.end());  
  8. // Print a message from the joining thread.  
  9. wcout << "Hello from the joining thread." << endl;  
  10. // Wait for the tasks to finish.  
  11. joinTask.wait(); 

这是有返回值的例子,注意when_all().then 的传入参数是vector<T>

  1. // Start multiple tasks.  
  2. array<task<int>, 3> tasks = {  
  3.     task<int>([] { return 88; }),  
  4.     task<int>([] { return 42; }),  
  5.     task<int>([] { return 99; })  
  6. };  
  7.  
  8. auto joinTask = when_all(tasks.begin(), tasks.end())  
  9.                 .then([](vector<int> results)  
  10.     {  
  11.         wcout << "The sum is "   
  12.               << accumulate(results.begin(), results.end(), 0)  
  13.               << L'.' << endl;  
  14.     });  
  15.  
  16. // Print a message from the joining thread.  
  17. wcout << "Hello from the joining thread." << endl;  
  18.  
  19. // Wait for the tasks to finish.  
  20. joinTask.wait(); 

when_all().wait()是当容器里面所有的task都被执行后,才继续向下执行。而when_any().wait()就是当容器里第一个task完成之后,就继续向下执行。和when_all 一样,when_any 要求task的返回值相同 。但是,when_any().then()的传入参数是pair<T, size_t> pair.first 是task的返回值,pair.second是已经完成的task的序号。

  1. // Start multiple tasks.  
  2. array<task<int>, 3> tasks = {  
  3.     task<int>([] { return 88; }),  
  4.     task<int>([] { return 42; }),  
  5.     task<int>([] { return 99; })  
  6. };  
  7.  
  8. // Select the first to finish.  
  9. when_any(tasks.begin(), tasks.end())  
  10.     .then([](pair<int, size_t> result)  
  11.     {  
  12.         wcout << "First task to finish returns " 
  13.               << result.first  
  14.               << L" and has index " 
  15.               << result.second  
  16.               << L'.' << endl;  
  17.     }).wait();    

这篇文章是这个系列的第一篇,旨在向大家介绍一些基本的概念和用法。我会在接下来的系列中,给大家展示一些更深层次的东西。

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

阅读更多
换一批

没有更多推荐了,返回首页