windows C++-高级并发和异步(一)
并发和异步的由来已经很久了,对于从xp开始编程的人来说,这个概念并不陌生,但问题在于,在早期,这两个技术被认为是操作系统提供的服务,而非编程语言的概念。
事情发生变化的原因,和C++标准不断变迁的原因类似,编程语言的演化是更加倾向于人类语言而不是倾向于机器语言,当开发的效率压过运行的效率的时候,这种编程语言越做越大就更加的明显了。但需要注意黑体字的前提,因为在许多特殊行业中,运行的效率是压过开发的效率的。
编程语言的演化是两个方向的,要么越来越接近底层,要么越来越接近上层。
将工作卸载到 Windows 线程池
协同例程与任何其他函数的类似之处在于,调用方将会阻塞到某个函数向其返回了执行为止。 另外,协同例程返回的第一个机会是第一个 co_await、co_return 或 co_yield。
因此,在协同例程中执行受计算限制的工作之前,需要将执行返回给调用方(换句话说,引入暂停点),使调用方不被阻塞。 如果还没有对其他某个操作运行 co_await 来做到这一点,则可以对 winrt::resume_background 函数运行 co_await。 这会将控制权返回给调用方,然后立即在某个线程池线程上恢复执行。
实现中使用的线程池是底层 Windows 线程池,因此具有极高的效率。
IAsyncOperation<uint32_t> DoWorkOnThreadPoolAsync()
{co_await winrt::resume_background(); // Return control; resume on thread pool.uint32_t result;for (uint32_t y = 0; y < height; ++y)for (uint32_t x = 0; x < width; ++x){// Do compute-bound work here.}co_return result;
} 
编程时仔细考虑线程相关性
该方案继续对上一个方案进行扩展。 你已将一些工作卸载到线程池,但希望在用户界面 (UI) 中显示进度。
IAsyncAction DoWorkAsync(TextBlock textblock)
{co_await winrt::resume_background();// Do compute-bound work here.textblock.Text(L"Done!"); // Error: TextBlock has thread affinity.
} 
上述代码抛出一个 winrt::hresult_wrong_thread 异常,因为必须从创建 TextBlock 的线程(即 UI 线程)更新 TextBlock。 一种解决方案是捕获最初调用协同例程的线程上下文。 为此,请实例化 winrt::apartment_context 对象,执行后台工作,然后对 apartment_context 运行 co_await 以切回到调用上下文。
IAsyncAction DoWorkAsync(TextBlock textblock)
{winrt::apartment_context ui_thread; // Capture calling context.co_await winrt::resume_background();// Do compute-bound work here.co_await ui_thread; // Switch back to calling context.textblock.Text(L"Done!"); // Ok if we really were called from the UI thread.
} 
只要上面的协同例程是从创建 TextBlock 的 UI 线程调用的,这种方法是可行的。 在应用中,有很多时候都是可以保证这一点的。
若要通过某种更通用的解决方案来更新 UI(包括不确定调用线程的情况)可以对 winrt::resume_foreground 函数运行 co_await,以切换到特定的前台线程。 在以下代码示例中,我们通过传递与 TextBlock 关联的调度程序对象(通过访问其 Dispatcher 属性)来指定前台线程。 winrt::resume_foreground 实现对该调度程序对象调用 CoreDispatcher.RunAsync,以执行协同例程中该调度程序对象之后的工作。
IAsyncAction DoWorkAsync(TextBlock textblock)
{co_await winrt::resume_background();// Do compute-bound work here.// Switch to the foreground thread associated with textblock.co_await winrt::resume_foreground(textblock.Dispatcher());textblock.Text(L"Done!"); // Guaranteed to work.
} 
winrt::resume_foreground 函数采用可选的优先级参数。 如果使用该参数,则可以使用上面所示的模式。 如果不使用,则可以选择将 co_await winrt::resume_foreground(someDispatcherObject); 简化为 co_await someDispatcherObject;。
协同例程中的执行上下文、恢复和切换(上)
概括地说,在协同例程中某个暂停点之后,原始执行线程可能会消失,而恢复可能会在任何线程上发生(换而言之,任何线程都可以针对异步操作调用 Completed 方法)。
但是,如果对四个 Windows 运行时异步操作类型 (IAsyncXxx) 中的任何一个运行 co_await,则 C++/WinRT 会在运行 co_await 时捕获调用上下文。 另外,它可以当延续操作恢复时,你仍处于该上下文中。 为此,C++/WinRT 会检查你是否已进入调用上下文,如果没有,则切换到该上下文。 如果在运行 co_await 之前你处于单线程单元 (STA) 线程中,则运行之后你仍处于相同的线程中;如果在运行 co_await 之前你处于多线程单元 (MTA) 线程中,则运行之后你将处于不同的线程中。
IAsyncAction ProcessFeedAsync()
{Uri rssFeedUri{ L"https://blogs.windows.com/feed" };SyndicationClient syndicationClient;// The thread context at this point is captured...SyndicationFeed syndicationFeed{ co_await syndicationClient.RetrieveFeedAsync(rssFeedUri) };// ...and is restored at this point.
} 
可以依赖此行为的原因在于,C++/WinRT 提供相应的代码,使这些 Windows 运行时异步操作类型能够适应 C++ 协同例程语言支持(这些代码片段称为等待适配器)。 C++/WinRT 中剩余的可等待类型只是一些线程池包装器和/或帮助器;因此它们会在线程池中完成。
using namespace std::chrono_literals;
IAsyncOperation<int> return_123_after_5s()
{// No matter what the thread context is at this point...co_await 5s;// ...we're on the thread pool at this point.co_return 123;
} 
如果对其他某个类型运行 co_await,即使是在 C++/WinRT 协同例程实现中,则另一个库会提供适配器,你需要了解这些适配器在恢复和上下文方面的作用。
为了尽量减少上下文切换次数,可以使用本主题所述的某些方法。 让我们看看该操作的几个图示。 以下伪代码示例演示了一个事件处理程序的大纲。该处理程序调用 Windows 运行时 API 来加载图像,切换到后台线程来处理该图像,然后返回到 UI 线程以在 UI 中显示该图像。
IAsyncAction MainPage::ClickHandler(IInspectable /* sender */, RoutedEventArgs /* args */)
{// We begin in the UI context.// Call StorageFile::OpenAsync to load an image file.// The call to OpenAsync occurred on a background thread, but C++/WinRT has restored us to the UI thread by this point.co_await winrt::resume_background();// We're now on a background thread.// Process the image.co_await winrt::resume_foreground(this->Dispatcher());// We're back on MainPage's UI thread.// Display the image in the UI.
} 
这会带来额外的问题,在下一部分讲述。
相关文章:
windows C++-高级并发和异步(一)
并发和异步的由来已经很久了,对于从xp开始编程的人来说,这个概念并不陌生,但问题在于,在早期,这两个技术被认为是操作系统提供的服务,而非编程语言的概念。 事情发生变化的原因,和C标准不断变迁…...
Java FX 学习
声明:参考视频 一. Stage与Scene 舞台与场景:JavaFX应用程序将Ul容器定义为舞台(Stage)与场景(Scene)Stage类是顶级容器,它对应于窗体,其内容由Scene决定。Scene类是所有可视化内容…...
【走迷宫】
题目 DFS代码 #include<bits/stdc.h> using namespace std; const int N 110; int matrix[N][N]; int n, m; int dx[4] {-1, 0, 1, 0}, dy[4] {0, 1, 0, -1}; int dis[N][N]; void dfs(int x, int y, int cnt) {if(cnt > dis[n-1][m-1]) return;if(x n-1 &&a…...
linux(debian)迁移var数据到已分配逻辑卷的物理盘
文章目录 0 背景1 查看当前情况1.1 查看磁盘空间1.2 列出所有可用块设备的信息,而且还能显示他们之间的依赖关系1.3 查看可用磁盘1.4 查看卷组 2 卷组中创建逻辑卷3 创建文件系统4 创建临时文件夹并挂载,然后备份源文件5 修改开机挂载配置5.1 查看原配置…...
【产品那些事】什么是应用程序安全态势管理(ASPM)?
文章目录 前言当前应用安全(AppSec)推进遇到的问题关于ASPM的定义 为什么需要ASPM:B端客户核心需求ASPM产品关键策略理想状态下的ASPMASPM与CSPM的区别国内外产品参考 前言 随着现代软件开发实践的快速演变,特别是在敏捷开发和 DevOps 的推动下…...
cocosUI多分辨率适配
需求:由于各个设备的分辨率和尺寸并不一样,所以需要一套适配系统去很好的针对不同的设备分辨率或尺寸进行适配,以给玩家一个很好的游戏体验。 目前的主流适配方案 目前,针对不同设备的适配,主流的方案通常包括以下几种…...
无法加载到主类
说明:记录一次项目启动错误,如下: 错误信息:错误: 找不到或无法加载主类 com.hezy.App 原因: java.lang.ClassNotFoundException: com.hezy.App 解决:首先,在项目中勾选这个,显示target文件夹 …...
深入理解Kafka核心设计与实践原理_03
深入理解Kafka核心设计与实践原理_03 03_消费者3.1消费者与消费者组3.2客户端开发3.2.1 必要的参数配置3.2.2 订阅主题与分区 草稿 03_消费者 与生产者对应的是消费者,应用程序可以通过KafkaConsumer来订阅主题,并从订阅的主题中拉取消息。不过在使用Ka…...
MySQL- 覆盖索引
覆盖索引(Covering Index)是 MySQL 中的一种优化技术,它能够显著提高查询性能。在使用覆盖索引的情况下,查询操作只需要访问索引即可获取所需的数据,而不必再访问表的实际数据行(即不需要回表)。…...
JSON与EXL文件互转
功能:实现json到excel文件的相互转换(支持json多选版) 目的:编码与语言对应,方便大家使用 页面设计: 介绍: 1.选择文件栏目选择想要转换的文件 2.生成路径是转换后文件所在目录 3.小方框勾选与不勾选分别代表exl到…...
后台管理权限自定义按钮指令v-hasPermi
第一步:在src下面建立一个自定义指令文件,放自定义指令方法 permission.js文件: /*** v-hasPermi 操作权限处理*/import store from "/store";export default {inserted(el, binding) {const { value } binding;//从仓库里面获取到后台给的数组const permission s…...
【Python绘制散点图并添加趋势线和公式以及相关系数和RMSE】
在Python中,绘制散点图并添加趋势线(通常是线性回归线)、公式、以及相关系数(Pearson Correlation Coefficient)和均方根误差(RMSE)可以通过结合matplotlib用于绘图,numpy用于数学运…...
linux bridge VLAN
TP-Link 支持 Linux 桥接(bridge)和 VLAN 功能的产品主要包括其高端的交换机和一些企业级路由器: TP-Link JetStream 系列交换机: TL-SG3424: 24端口千兆交换机,支持 VLAN 和桥接。TL-SG3210: 24端口千兆管理型交换机&…...
Java进阶篇之深入理解多态的概念与应用
引言 在Java面向对象编程(OOP)中,多态(Polymorphism)是一个关键概念,它允许相同类型的对象在不同的场景中表现出不同的行为。多态不仅增强了代码的灵活性和可扩展性,还极大地提高了代码的可维护…...
Linux下的进程调度队列
我们在进程那一篇讲到了操作系统时间片轮换调度的概念 那么Linux下具体是怎么调度的?...
统计回归与Matlab软件实现上(一元多元线性回归模型)
引言 关于数学建模的基本方法 机理驱动 由于客观事物内部规律的复杂及人们认识程度的限制,无法得到内在因果关系,建立合乎机理规律的数学模型数据驱动 直接从数据出发,找到隐含在数据背后的最佳模型,是数学模型建立的另一大思路…...
【项目】基于Vue3.2+ElementUI Plus+Vite 通用后台管理系统
构建项目 环境配置 全局安装vue脚手架 npm install -g vue/cli-init打开脚手架图形化界面 vue ui创建项目 在图形化界面创建项目根据要求填写项目相关信息选择手动配置勾选配置项目选择配置项目然后我们就搭建完成啦🥳,构建可能需要一点时间࿰…...
随机生成 UUID
1、随机生成 UUID主方法 /*** 随机生成 UUID* param {*} len 生成字符串的长度* param {*} radix 生成随机字符串的长度**/export function uuid_(len 30, radix 20) {var chars 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.split()var uuid [],ir…...
报名表EXCEL图片批量下载源码-CyberWinApp-SAAS 本地化及未来之窗行业应用跨平台架构
每次报名表都会包含大量照片,一张一张下载很慢 可以通过未来之窗开源平台架构 开开excel批量下载 实现代码也很简单 function 未来之窗下载(){ let 未来之窗地址 document.getElementById("batchurl").value; let 保存路径 document.getElementById(…...
SpringBoot 整合 Elasticsearch 实现商品搜索
一、Spring Data Elasticsearch Spring Data Elasticsearch 简介 Spring Data Elasticsearch是Spring提供的一种以Spring Data风格来操作数据存储的方式,它可以避免编写大量的样板代码。 常用注解 常用注解说明如下: 注解名称 作用 参数说明 Docu…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
腾讯云V3签名
想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
React父子组件通信:Props怎么用?如何从父组件向子组件传递数据?
系列回顾: 在上一篇《React核心概念:State是什么?》中,我们学习了如何使用useState让一个组件拥有自己的内部数据(State),并通过一个计数器案例,实现了组件的自我更新。这很棒&#…...
【版本控制】GitHub Desktop 入门教程与开源协作全流程解析
目录 0 引言1 GitHub Desktop 入门教程1.1 安装与基础配置1.2 核心功能使用指南仓库管理日常开发流程分支管理 2 GitHub 开源协作流程详解2.1 Fork & Pull Request 模型2.2 完整协作流程步骤步骤 1: Fork(创建个人副本)步骤 2: Clone(克隆…...
SQL进阶之旅 Day 22:批处理与游标优化
【SQL进阶之旅 Day 22】批处理与游标优化 文章简述(300字左右) 在数据库开发中,面对大量数据的处理任务时,单条SQL语句往往无法满足性能需求。本篇文章聚焦“批处理与游标优化”,深入探讨如何通过批量操作和游标技术提…...
Netty自定义协议解析
目录 自定义协议设计 实现消息解码器 实现消息编码器 自定义消息对象 配置ChannelPipeline Netty提供了强大的编解码器抽象基类,这些基类能够帮助开发者快速实现自定义协议的解析。 自定义协议设计 在实现自定义协议解析之前,需要明确协议的具体格式。例如,一个简单的…...
【自然语言处理】大模型时代的数据标注(主动学习)
文章目录 A 论文出处B 背景B.1 背景介绍B.2 问题提出B.3 创新点 C 模型结构D 实验设计E 个人总结 A 论文出处 论文题目:FreeAL: Towards Human-Free Active Learning in the Era of Large Language Models发表情况:2023-EMNLP作者单位:浙江大…...
