在这一章中,我们讨论一下如何创建和使用一个异步的WinRT API。

在WinRT中有四种异步的接口,IAsyncAction 没有返回值类型的接口,IAsyncActionWithProgress<TProgress> 没有返回值类型,但是有进度监视器的接口。IAsyncOperation<TResult> 返回值为T的接口,IAsyncActionOperationWithProgress<TResult,TProgress> 返回值为T,有进度监视器的接口。

之前我们说过,在WinRT中可以使用task来调用IAsyncAction 等接口,但是有一些其他的功能被限制,比如:

1. 在WinRT中task只能用.then来加入前面的task执行成功之后的行为。task.wait函数不可以使用。

2. progress_reporter不能在task里面使用。

3. cancellation_taken,可以作为传入参数在task里面使用。

cancellation_token_source fileTaskTokenSource;

// Cancel button event handler:
fileTaskTokenSource.cancel();

// task chain

task<StorageFile^> getFileTask(storageFolder->GetFileAsync(), fileTaskTokenSource.get_token());

4. 错误的捕获要在.then的方法里面进行

StorageFolder^ documentsFolder = KnownFolders::DocumentsLibrary;
    task<StorageFile^> getFileTask(documentsFolder->GetFileAsync(fileName));

getFileTask.then([](StorageFile^ storageFileSample) {       
        return storageFileSample->DeleteAsync();
    }).then([](task<void> t) {

try
        {
            t.get();

// .get() didn't throw, so we succeeded.
            OutputDebugString(L"File deleted.");
        }
        catch (Exception^ e)
        {
                 //Example output: The system cannot find the specified file.
                 OutputDebugString(e->Message->Data());
        }

});

上面的部分说了一些在用IAsyncAction的注意事项。接着我们讲讲如何写IAsyncAction等方法。

我们需要用 create_async去创建IAsyncAction等返回值类型的异步操作。关于create_async的传入参数和返回值,可以参照下面的表格

To create this Windows Runtime interface

Return this type fromcreate_async

Pass these parameter types to your work function to use an implicit cancellation token

Pass these parameter types to your work function to use an explicit cancellation token

IAsyncAction

void ortask<void>

(none)

(cancellation_token)

IAsyncActionWithProgress<TProgress>

void ortask<void>

(progress_reporter)

(progress_reporter,cancellation_token)

IAsyncOperation<TResult>

T or task<T>

(none)

(cancellation_token)

IAsyncActionOperationWithProgress<TResult
s, TProgress>

T or task<T>

(progress_reporter)

(progress_reporter,cancellation_token)

这里顺便要说的,create_async可以返回task<void>或者直接返回void,返回void的时候,lambda表达式里面的代码会在后台执行,同时这个async的方法可以被其他语言调用。当我们这段表达式里面含有异步操作的时候,我们就要用返回task,比如

IAsyncOperation<T>^ asyncOperation = create_async( []() {
    return create_task(FirstAsync(...))
    .then( [](X val){
        return SecondAsync(val, ...);
    }).then( [](Y val)
        return ThirdAsync(val, ...);
    });

});

这段代码会执行FirstAsync->SecondAsync->ThirdAsync,最后返回的是 ThirdAsync的结果。

我们可以创建一个有返回值,有取消操作,有进度监视器,可以抛出错误的 IAsyncActionOperationWithProgress 函数如下

IAsyncOperationWithProgress<int,String^>^ TestWithProgressAsync(int input)
{
    return create_async([input](progress_reporter<String^> reporter) {
        if(input==0)
             throw ref new InvalidArgumentException();
        bool moreToDo = true;
        while (moreToDo)
        {
            // Check for cancellation.
            if (is_task_cancellation_requested()) {                
                // Cancel the current task.
                cancel_current_task();
                return 32;
                moreToDo = false;
            }
            else {
                // Perform work.
                reporter.report("Running");
            }
        }
        reporter.report("Finished");
        return 42;
    });

}

progress_reporter<T> reporter 作为传入参数,这个T可以是各种类型,[input] 是为了绑定传入参数,is_task_cancellation_requested()捕获取消事件, reporter.report(T)汇报进度。

接着我们演示在WinRT中如何使用这个异步函数,使用这个异步函数有两种方式,一是通过task 封装,就如同文章开头所说,二是通过调用纯WinRT接口。

首先,我们演示一下如何用task的方式去调用这个异步函数。

首先,声明和初始化一个task和cancellation

// In BlankPage.xaml.h

cancellation_token_source TaskTokenSource;
        task<int> t;

// In BlankPage.xaml.cpp

BlankPage::BlankPage()
{
    InitializeComponent();
    // TestWithProgressAsync(0) will throw a execption
    t=task<int>(TestWithProgressAsync(1),TaskTokenSource.get_token());
}

接着,拖一个cancel和except按钮还有一个名字是result 的TextBlock,在两个按钮的click事件中写入:

void Application3::BlankPage::Button_Click_Cancel(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)

{
    
    
    cancellation_token_registration cookie;
    auto token =TaskTokenSource.get_token();
     cookie = token.register_callback([this, token, &cookie]() {
         safe_cast<TextBlock^>(this->FindName("result"))->Text+="Cancel";
        // Although not required, demonstrate how to unregister 
        // the callback.
        token.deregister_callback(cookie);
    });
    TaskTokenSource.cancel();
}

void Application3::BlankPage::Button_Click_Except(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    int c=0;
    t.then([this,&c](task<int> t){
        try
        {
        
            int res=t.get();

c+=res;

safe_cast<TextBlock^>(this->FindName("result"))->Text+=res;
        }catch(Exception^ ex)
        {
            safe_cast<TextBlock^>(this->FindName("result"))->Text+=ref new String(ex->Message->Data());
        }
    },task_continuation_context::use_arbitrary());
}

这里要注意的几点是:

1. task里面无法使用进度监视器。

2. 我们可以通过注册token的callback 函数来处理cancel之后的行为,在不改变原始函数的情况下。上面的例子中,我们用callback函数来修改TextBlock里面的内容。

3. 我们只有在 t.then([this](task<int> t) 这种情况下才可以使用t.get(),如果我们直接使用Application3::BlankPage::t.get()会报错。

4. 如果我们在想使用.then 外面的变量,比如Button_Click_Except函数里面的 int c,我们不仅仅需要绑定[this,&c](task<int>, 我们还需在then方法里面加入task_continuation_context::use_arbitrary()这个参数。这是因为XAML的UI线程都是STA的,而Lambda表达式是MTA,所以两者之间共享数据默认是不可以的。所以就需要task_continuation_context::use_arbitrary()这个参数来修改这个默认行为。

我们再来看看如何用WinRT的namespace里面的接口来调用这个异步函数。

首先,要声明一个 Windows::Foundation::IAsyncOperationWithProgress<int,Platform::String^>^ AsyncOper; 在头文件里,这里注意如果没有引用Platform命名空间的话,一定要在Sting^前面加上这个命名空间,否则编译会报错。

然后在cpp文件里

BlankPage::BlankPage()

{
    InitializeComponent();
    // TestWithProgressAsync(0) will throw a execption
    AsyncOper=TestWithProgressAsync(0);

AsyncOper->Progress=ref new AsyncOperationProgressHandler<int,String^>(
        [this](IAsyncOperationWithProgress<int,String^>^ pretask,  String^ progressInfo){
            safe_cast<TextBlock^>(this->FindName("result"))->Text+=progressInfo+"\n";

});

AsyncOper->Completed=ref new AsyncOperationWithProgressCompletedHandler<int,String^>(
        [this](IAsyncOperationWithProgress<int,String^>^ pretask, AsyncStatus asyncStatus){
            if(asyncStatus==AsyncStatus::Completed)
            {
                int res=pretask->GetResults();
            }
            if(asyncStatus==AsyncStatus::Canceled)
            {
                safe_cast<TextBlock^>(this->FindName("result"))->Text="Cancel";
            }
            if(asyncStatus==AsyncStatus::Error)
            {
                try
                {
                    int res=pretask->GetResults();

}catch(Exception^ ex)
                {
                    safe_cast<TextBlock^>(this->FindName("result"))->Text+=ref new String(ex->Message->Data());
                }
            }
    });
}

void Application3::BlankPage::Button_Click_Cancel(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    AsyncOper->Cancel();
}

我们通过AsyncOper->Progress=ref new AsyncOperationProgressHandler 来添加进度监视器

通过AsyncOper->Completed=ref new AsyncOperationWithProgressCompletedHandler 添加完成事件的委托,然后我们判断asyncStatus的三个状态,来做出不同的反应。

通过AsyncOper->Cancel()来取消异步操作。

这里面要强调的是错误的捕获要用类似于task的方法,既try-catch块。IAsyncInfo.ErrorCode 这个属性得到的值是未初始化的。

最后,本文介绍了如何写和如何调用一个WinRT的异步操作,希望这篇文章能给大家在使用WinRT异步API的时候提供一些帮助。

引用自:

http://msdn.microsoft.com/en-us/magazine/hh781020.aspx

http://msdn.microsoft.com/en-us/library/windows/apps/hh780559.aspx

http://msdn.microsoft.com/en-us/library/windows/apps/hh750082.aspx

http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/8061242d-0e96-4d9d-8743-563291ef8088/

转载于:https://www.cnblogs.com/zjjcy/archive/2012/05/13/2489298.html

C++异步编程 for VS2011(四)相关推荐

  1. 【C++】多线程与异步编程【四】

    文章目录 [C++]多线程与异步编程[四] 0.三问 1.什么是异步编程? 1.1同步与异步 1.2 **阻塞与非阻塞** 2.如何使用异步编程 2.1 使用全局变量与条件变量传递结果 实例1: 2. ...

  2. (转)javascript异步编程的四种方法

    本文转自:http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html 作者:阮一峰 本文仅仅作为个人mark ...

  3. .NET异步编程总结----四种实现模式

    最近很忙,既要外出找工作又要兼顾老板公司的项目.今天在公司,忙里偷闲,总结一下.NET中的异步调用函数的实现方法,DebugLZQ在写这篇博文之前自己先动手写了本文的所有示例代码,开写之前是做过功课的 ...

  4. JavaScript异步编程的四种方法(转)

    作者: 阮一峰 日期: 2012年12月21日 你可能知道,Javascript语言的执行环境是"单线程"(single thread). 所谓"单线程",就是 ...

  5. JS-Js异步编程四种方法

    文章目录 前言 同步和异步 一.回调函数 二.事件监听 三.发布/订阅 四.Promises对象 学而不思则罔 前言 工作一段时间,发现自己对异步编程理解的并没有很透彻,翻看众多博客,参考阮一峰老师博 ...

  6. .NET中的异步编程(四)- IO完成端口以及FileStream.BeginRead

    本文首发在IT168 写这个系列原本的想法是讨论一下.NET中异步编程风格的变化,特别是F#中的异步工作流以及未来的.NET 5.0中的基于任务的异步编程模型.但经过三篇文章后很多人对IO异步背后实现 ...

  7. 异步编程模型--使用 IAsyncResult 对象

    先推荐阅读下面的资料: MSDN:异步编程设计模式 IBM developerworks: 使用异步 I/O 大大提高应用程序的性能 参考博文: 1.正确使用异步操作 2.Lab:体会ASP.NET异 ...

  8. 笑了,面试官问我知不知道异步编程的Future。

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 荒腔走板 老规矩,先来一个简短的荒腔走板,给冰冷的技术文注 ...

  9. 深入理解javascript异步编程障眼法h5 web worker实现多线程

    0.从一道题说起 var t = true; setTimeout(function(){ t = false; }, 1000); while(t){ } alert('end'); 1 2 3 4 ...

最新文章

  1. ps怎么把一个颜色替换成另一个颜色_图标设计,用PS制作一款小清新的拟物时钟...
  2. 机器人编程语言python-10大热门机器人编程语言,你掌握了哪种?
  3. [Python]元组与列表的区别及内建用法
  4. redis install note
  5. 01.elasticsearch请求使用的基本语法
  6. 黑龙江对口学计算机上机,2009年黑龙江省职高对口升学计算机应用专业技能试卷十.doc...
  7. STM32-SPI通信
  8. python 输出文字_Python中输出ASCII大文字、艺术字、字符字小技巧
  9. 常年“盘踞”数据库前五的 MongoDB,在中国有哪些新动向?
  10. wincc安装信息服务器,WinCC 7.4软件不会安装?怎么授权?一文教会你
  11. 伺服速度控制模式接线图_伺服控制的三种模式,接线方式与参数设置的讲解
  12. 搞死SAP系统系列 让系统无法连接数据库
  13. 平凡程序员一年又一年的感悟(2019)
  14. 数据校验之Checksum算法
  15. 985 211计算机考研科目,考研想上985/211,你各科分数至少要考这么多!
  16. FFmpeg c++ 报错合集
  17. 机械硬盘速度测试软件用哪个,比机械硬盘快多少? SSD测量了常用软件和应用速度...
  18. STemWin专题--画直线
  19. 配置微信小程序开发分享朋友圈功能
  20. c++ const 转非const

热门文章

  1. windows vista 下载
  2. 手机上能翻译C语言的app,如何在手机上实现中英在线翻译?
  3. Generator函数语法
  4. POJ1087A Plug for UNIX(会议室的插座)——最大流
  5. Golang包管理工具(四)之go-modules的使用
  6. Axure this is most likely not a valida .rp file
  7. 铁道中文应用开发现状综述
  8. 红米k30 允许调用gpu调试层_2499元的红米K30S至尊纪念版,会是性价比最高的865神机吗?...
  9. 基于MATLAB编写的GNSS_SDR(GNSS软件接收机)——自学笔记(2)
  10. YOLOv1的loss函数