C++異步編程 for VS2011(二)


在上一篇文章中,我介紹一些在VS中C++異步編程的簡單概念和語法。這篇,我們討論一下異步編程中取消操作的概念。

 

取消操作:

取消一個正在進行的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

 

 


免責聲明!

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



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