zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    CKeditor3.6.2 配置与精简
    CKEditor与CKFinder整合并实现文件上传功能
    实体关联关系映射:
    status pending状态
    wx:for
    小程序
    获取指定控件的值
    报表
    dataGridView 设置
    SQLite 的使用
  • 原文地址:https://www.cnblogs.com/zjjcy/p/2416700.html
Copyright © 2011-2022 走看看