当前位置: 首页 > news >正文

windows C++-并发和异步操作(上)

本文介绍协同例程和 co_await 的概念,我们建议你在 UI 应用程序和非 UI 应用程序中使用它们。 为了简单起见,本介绍主题中的大多数代码示例演示了 Windows 控制台应用程序 (C++/WinRT) 项目。 本文中后面的代码示例使用协同例程,但为方便起见,控制台应用程序示例还会在退出前继续使用阻止性的 get 函数调用,这样应用程序就不会在显示其输出之前退出。 不要通过 UI 线程这样做(调用阻止性的 get 函数), 而应使用 co_await 语句。 高级并发和异步主题介绍了将要在 UI 应用程序中使用的技术。

下面介绍了可通过 C++/WinRT 创建和使用 Windows 运行时异步对象的部分方式。注意,部分代码可能需要高版本的C++标准才不会报错。

异步操作和 Windows 运行时“Async”函数

有可能需要超过 50 毫秒才能完成的任何 Windows 运行时 API 将实现为异步函数(具有一个以“Async”结尾的名称)。 异步函数的实现会启动另一线程上的工作,并且会立即返回表示异步操作的对象。 在异步操作完成后,返回的对象会包含从该工作中生成的任何值。 Windows::Foundation Windows 运行时命名空间包含四种类型的异步操作对象。

  • IAsyncAction;
  • IAsyncActionWithProgress<TProgress>;
  • IAsyncOperation<TResult>;
  • IAsyncOperationWithProgress<TResult, TProgress>;

每种异步操作类型都将投影到 winrt::Windows::Foundation C++/WinRT 命名空间中的相应类型。 C++/WinRT 还包含内部 await 适配器结构。 不要直接使用它,但借助该结构,可以编写 co_await 语句以协作等待返回其中一种异步操作类型的任何函数的结果。 然后,可以自行创作返回这些类型的协同例程。

异步 Windows 函数的示例是 SyndicationClient::RetrieveFeedAsync,其返回类型 IAsyncOperationWithProgress<TResult, TProgress> 的异步操作对象。

让我们来看一些阻止和不阻止使用 C++/WinRT 来调用类似 API 的方法。 我们将在接下来的几个代码示例中使用 Windows 控制台应用程序 (C++/WinRT) 项目,只为说明基本的概念。 更适用于 UI 应用程序的技术在高级并发和异步中讨论。

阻塞调用线程

以下代码示例接收来自 RetrieveFeedAsync 的异步操作对象,并且在该对象上调用 get 以阻塞调用线程,直到异步操作的结果可用。

若要将此示例直接复制并粘贴到 Windows 控制台应用程序 (C++/WinRT) 项目的主源代码文件中,请先在项目属性中设置“不使用预编译的头文件”。

// main.cpp
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Web.Syndication.h>using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;void ProcessFeed()
{Uri rssFeedUri{ L"https://blogs.windows.com/feed" };SyndicationClient syndicationClient;SyndicationFeed syndicationFeed{ syndicationClient.RetrieveFeedAsync(rssFeedUri).get() };// use syndicationFeed.
}int main()
{winrt::init_apartment();ProcessFeed();
}

调用 get 可以方便编写代码,对于出于任何原因不想使用协同例程的控制台应用或后台线程来说,这是一种理想选择。 但这既不是并发也不是异步操作,因此不适合 UI 线程(如果试图在 UI 线程上使用它,会在未优化的版本中触发断言)。 为了避免占用 OS 线程执行其他有用的工作,我们需要另一种方法。

编写协同例程

C++/WinRT 将 C++ 协同例程集成到编程模型中以提供协作等待结果的自然方式。 可以通过编写协同例程来生成自己的 Windows 运行时异步操作。 在以下代码示例中,ProcessFeedAsync 是协同例程。

get 函数位于 C++/WinRT 投影类型 winrt::Windows::Foundation::IAsyncAction 中,因此你可以从任意 C++/WinRT 项目内部调用该函数。 你将找不到列为 IAsyncAction 接口成员的函数,因为 get 不属于实际 Windows 运行时类型 IAsyncAction 的应用程序二进制接口 (ABI) 设计面。

// main.cpp
#include <iostream>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;void PrintFeed(SyndicationFeed const& syndicationFeed)
{for (SyndicationItem const& syndicationItem : syndicationFeed.Items()){std::wcout << syndicationItem.Title().Text().c_str() << std::endl;}
}IAsyncAction ProcessFeedAsync()
{Uri rssFeedUri{ L"https://blogs.windows.com/feed" };SyndicationClient syndicationClient;SyndicationFeed syndicationFeed{ co_await syndicationClient.RetrieveFeedAsync(rssFeedUri) };PrintFeed(syndicationFeed);
}int main()
{winrt::init_apartment();auto processOp{ ProcessFeedAsync() };// do other work while the feed is being printed.processOp.get(); // no more work to do; call get() so that we see the printout before the application exits.
}

 协同例程是可以暂停和恢复的函数。 在上述 ProcessFeedAsync 协同例程中,当达到 co_await 语句时,该协同例程会异步启动 RetrieveFeedAsync 调用,然后立即暂停自身并将控件返回到调用方(上述示例中为 main)。 然后,main 可以继续执行工作,同时将检索并打印提要。 完成该操作(RetrieveFeedAsync 调用完成)后,ProcessFeedAsync 协同例程将在下一个语句中恢复。

可以将一个协同例程聚合到其他协同例程中。 或者,也可以调用 get 以阻塞和等待其完成(以及获得结果,如果有)。 或者,可以将其传递到支持 Windows 运行时的其他编程语言。

也可以通过使用委托来处理异步操作的已完成和/或正在进行中的事件。 

正如你所看到的,在上面的代码示例中,我们在退出 main 之前继续使用阻止性的 get 函数调用。 但是,这只是为了让应用程序不会在显示其输出之前退出。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
  • 汇量科技Mintegral发布全新产品矩阵:助力广告主高效增长与变现
  • go-zero中基本配置及获取参数
  • django.core.management.base.SystemCheckError
  • 阿布吞的基础使用——Ubuntu
  • 格式化字符串漏洞
  • 基于Qt的osg读取模型进度回调
  • 数据结构:栈(含源码)
  • [QNX] C++编程: 外部硬件加速器与SOC共享内存中使用NOCACHE的必要性与优化策略
  • jQuery实现图片轮播效果
  • Redis相关面试题(二)
  • Go框架选战:Gin、Echo、Fiber的终极较量
  • 力扣 | 递增子序列 | 动态规划 | 最长递增子序列、最长递增子序列的个数、及其变式
  • Python-调用pymysql库,执行插入语句
  • 3个月,从Web前端到鸿蒙应用高手
  • ----------
  • 【翻译】babel对TC39装饰器草案的实现
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • CentOS从零开始部署Nodejs项目
  • IP路由与转发
  • JavaScript设计模式之工厂模式
  • Java新版本的开发已正式进入轨道,版本号18.3
  • MySQL QA
  • php ci框架整合银盛支付
  • PHP的类修饰符与访问修饰符
  • tweak 支持第三方库
  • vuex 学习笔记 01
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • webpack4 一点通
  • 大快搜索数据爬虫技术实例安装教学篇
  • 搞机器学习要哪些技能
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 鱼骨图 - 如何绘制?
  • 7行Python代码的人脸识别
  • zabbix3.2监控linux磁盘IO
  • 我们雇佣了一只大猴子...
  • # Panda3d 碰撞检测系统介绍
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #systemverilog# 之 event region 和 timeslot 仿真调度(十)高层次视角看仿真调度事件的发生
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • #考研#计算机文化知识1(局域网及网络互联)
  • $forceUpdate()函数
  • (二)linux使用docker容器运行mysql
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (原創) 未来三学期想要修的课 (日記)
  • (转)程序员技术练级攻略
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .aanva
  • .Net IE10 _doPostBack 未定义
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET(C#) Internals: as a developer, .net framework in my eyes
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .net快速开发框架源码分享
  • .NET与java的MVC模式(2):struts2核心工作流程与原理
  • [012-1].第12节:Mysql的配置文件的使用