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

發佈了24 篇原創文章 · 獲贊 18 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章