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

取消操作:

取消一个正在进行的task,方式大概分两种,一种是从内部取消,另外一种是从外部取消。

我们通过cancel_current_task  去从内部取消这个task

 #include <ppltasks.h>

复制代码
#include <iostream>
#include <array>
#include <list>
using  namespace Concurrency;
using  namespace std;

void do_work()
{
     //  Simulate work.
    wcout << L " Performing work... " << endl;
    wait( 250);
}

int _tmain( int argc, _TCHAR* argv[])
{
         wcout << L " Creating task... " << endl;
        task< void> t([]() {
         bool moreToDo =  true;
         int i= 0;
         while (moreToDo)
        {
            i++;
             if(i== 4)
            {
                wcout<<L " In cancellation "<<endl;
                 //  call this function to cancel
                cancel_current_task();                                
            }
            do_work();
        }        
    });
 
    wait( 1000);
}
复制代码

 

这里要说明一点的是,在我们声明这个task之后,我们并没有调用.wait() 或者.get() 去执行他。只是调用了wait(1000);这个task就被执行了。这个是因为,wait(1000)这个函数,表面上是让当前的线程休息1000毫秒,但是他会激发后台scheduled状态的task,当这个task声明之后,他的状态就是scheduled,当我们在主线程调用wait()的方法,之前声明的task就会被激发和执行,所以我们不需要调用.wait()或者.get()去执行他。

 

如果我们想从外部取消这个task,我们需要传一个token给这个task,然后我们通过 cancellation_token_source::cancel 这个方法去取消这个task

     wcout << L"Creating task..." << endl;

复制代码

    cancellation_token_source cts;
    auto token=cts.get_token();
    task< void> t([]() {

         bool moreToDo =  true;
         while (moreToDo)
        {
             //  Simulate work.
            do_work();
        }        
    },token);

    wait( 1000);
    cts.cancel();
     //    Wait for the task to cancel.
    wcout << L " Waiting for task to complete... " << endl;
    t.wait();

    wcout << L " Done. " << endl;
     return  0;
复制代码

 

 在外部取消这个task的过程中,我们想在内部获得取消这个动作的信号。我们可以通过is_task_cancellation_requested 函数去获取

复制代码
    task< void> t([]() {

         bool moreToDo =  true;
         while (moreToDo)
        {
             //  Check for cancellation.
             if (is_task_cancellation_requested()) {   

                wcout << L " Get the cancel event " << endl;
                 //  Cancel the current task.
                cancel_current_task();

                 //  You must end this task in front line or in this line
                moreToDo =  false;

            }
             else {
                 //  Perform work.
                do_work();
            }
        }        
    }, token);

     //  Wait for one second and then cancel the task.
    wait( 1000);

    wcout << L " Canceling task... " << endl;
    cts.cancel();

   //    Wait for the task to cancel.
   wcout << L " Waiting for task to complete... " << endl;
   t.wait();
复制代码


这里要注意的是, 当我们调用cts.cancel()的时候,is_task_cancellation_requested 返回true,但是这个task并没有被取消,我们必须要在task里面手动调用cancel_current_task,或者通过其他办法让函数结束。如果我们不判断is_task_cancellation_requested  就不需要我们在task内部手动取消。

 

 我们还可以注入callback 函数,在我们尝试外部取消的时候。

复制代码
    cancellation_token_source cts;
    auto token=cts.get_token();
    cancellation_token_registration cookie;
    cookie=token.register_callback([](){ wcout << L " In cancellation callback... " << endl;});
    task< void> t([]() {

         bool moreToDo =  true;
         while (moreToDo)
        {
             //  Simulate work.
            do_work();
        }        
    },token);

    wait( 1000);
    cts.cancel();
复制代码

    token.deregister_callback(cookie); 

 

 以上的例子都是基于while循环的,我认为这样可以便于理解。同样,我们也可以用event,在Concurrency namespace里面,系统事件已经被封装成event Class (Concurrency Runtime) 这个类,有set wait 等方法便于使用。下面的例子就是基于event 和callback函数的

复制代码
              
//  task-cancellation-callback.cpp
//  compile with: /EHsc
#include <ppltasks.h>
#include <iostream>

using  namespace Concurrency;
using  namespace std;

int wmain()
{
    cancellation_token_source cts;
    auto token = cts.get_token();

     //  An event that is set in the cancellation callback.
     event e;

    cancellation_token_registration cookie;
    cookie = token.register_callback([&e, token, &cookie]() {

        wcout << L " In cancellation callback... " << endl;
        e. set();

         //  Although not required, demonstrate how to unregister 
        
//  the callback.
        token.deregister_callback(cookie);
    });

    wcout << L " Creating task... " << endl;

     //  Create a task that waits to be canceled.    
    task< void> t([&e]() {
        e.wait();
    }, token);

     //  Cancel the task.
    wcout << L " Canceling task... " << endl;
    cts.cancel();

     //  Wait for the task to cancel.
    t.wait();

    wcout << L " Done. " << endl;
复制代码

 这里还要注意deregister_callback,传入参数必须是引用类型。

 

最后关于取消操作,还要说一点就是如何给一个parallel_for 添加取消动作,首先,这个函数本是是没有支持取消操作的,我们要给他外面套一层task,通过取消外面的task,来取消里面的parallel_for。

复制代码
int wmain()
{
    cancellation_token_source cts;

     //
    
//  Run a parallel_for loop in a call to run_with_cancellation_token.
    wcout << L " Running a task with a cancellation token... " << endl;
    run_with_cancellation_token([cts] {

         //  For illustration, cancel the overall operation on the third
        
//  iteration of a parallel loop. The parallel_for call implicitly
        
//  inherits the cancellation token of the parent task.
         long counter =  0;
        parallel_for( 0100, [cts, &counter]( int n) {
             if (InterlockedIncrement(&counter) ==  3)
            {
                wstringstream ss;
                ss << L " Canceling... " << endl;
                wcout << ss.str();

                cts.cancel();
            }

            wstringstream ss;
            ss << L " In iteration  " << n << L "  of parallel_for... " << endl;
            wcout << ss.str();            
        });
    }, cts.get_token());

    wcout << L " Done. " << endl;
复制代码

 

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

你可能感兴趣的:(编程,concurrency,callback,token,parallel,2010)