windows C++ 并行编程-并发和UWP(三)

news2024/11/14 15:22:06
控制执行线程

Windows 运行时使用 COM 线程模型。 在此模型中,根据对象处理其同步的方式,对象被托管在不同的单元中。 线程安全对象托管在多线程单元 (MTA) 中。 必须通过单个线程访问的对象托管在单线程单元 (STA) 中。

在具有 UI 的应用程序中,ASTA(应用程序 STA)线程负责发送窗口消息而且它是进程中唯一可以更新 STA 托管的 UI 控件的线程。 这会产生两种后果。 第一种是,要使应用程序保持响应状态,所有占用大量 CPU 的操作和 I/O 操作都不应在 ASTA 线程上运行。 第二种是,来自后台线程的结果都必须封送回 ASTA 以更新 UI。 在 C++ UWP 应用中,MainPage 和其他 XAML 页面都在 ATSA 中运行。 因此,在 ASTA 中声明的任务延续默认情况下也会在此运行,因此您可以在延续主体中直接更新控件。 但是,如果在另一个任务中嵌套任务,则此嵌套任务中的任何延续都在 MTA 中运行。 因此,您需要考虑是否显式指定这些延续在什么上下文中运行。

从异步操作创建的任务(如 IAsyncOperation<TResult>),使用了特殊语义,可以帮助您忽略线程处理详细信息。 虽然操作可能会在后台线程上运行(或者它可能根本不由线程支持),但其延续在默认情况下一定会在启动了延续操作的单元上运行(换言之,从调用了 task::then的单元运行)。 可以使用 concurrency::task_continuation_context 类来控制延续的执行上下文。 使用这些静态帮助器方法来创建 task_continuation_context 对象:

  • 使用 concurrency::task_continuation_context::use_arbitrary 指定延续在后台线程上运行;
  • 使用 concurrency::task_continuation_context::use_current 指定延续在调用了 task::then的线程上运行;

可以将 task_continuation_context 对象传递给 task::then 方法以显式控制延续的执行上下文,或者可以将任务传递给另一单元,然后调用 task::then 方法以隐式控制执行上下文。

由于 UWP 应用的主 UI 线程在 STA 下运行,因此在该 STA 中创建的延续默认情况下在 STA 中运行。 相应地,在 MTA 中创建的延续将在 MTA 中运行。

下面一节介绍一种应用程序,该应用程序从磁盘读取一个文件,查找该文件中最常见的单词,然后在 UI 中显示结果。 最终操作(更新 UI)将在 UI 线程上发生。

此行为特定于 UWP 应用。 对于桌面应用程序,您无法控制延续的运行位置。 相反,计划程序会选择要运行每个延续的辅助线程。

对于在 STA 中运行的延续的主体,请不要调用 concurrency::task::wait 。 否则,运行时会引发 concurrency::invalid_operation ,原因是此方法阻止当前线程并可能导致应用停止响应。 但是,你可以调用 concurrency::task::get 方法来接收基于任务的延续中的先行任务的结果。

示例:使用 C++ 和 XAML 在 Windows 运行时应用中控制执行

假设有一个 C++ XAML 应用程序,该应用程序从磁盘读取一个文件,在该文件中查找最常见的单词,然后在 UI 中显示结果。 若要创建此应用,请首先在 Visual Studio 中创建“空白应用(通用 Windows)”项目并将其命名为 CommonWords。 在应用程序清单中,指定“文档库” 功能以使应用程序能够访问“文档”文件夹。 同时将文本 (.txt) 文件类型添加到应用程序清单的声明部分。 有关应用功能和声明的详细信息,请参阅 Windows 应用的打包、部署和查询。

更新 MainPage.xaml 中的 Grid 元素,以包含 ProgressRing 元素和 TextBlock 元素。 ProgressRing 指示操作正在进行, TextBlock 显示计算的结果。

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <ProgressRing x:Name="Progress"/>
    <TextBlock x:Name="Results" FontSize="16"/>
</Grid>

将以下 #include 语句添加到 pch.h。

#include <sstream>
#include <ppltasks.h>
#include <concurrent_unordered_map.h>

将以下方法声明添加到 MainPage 类 (MainPage.h)。

private:
    // Splits the provided text string into individual words.
    concurrency::task<std::vector<std::wstring>> MakeWordList(Platform::String^ text);

    // Finds the most common words that are at least the provided minimum length.
    concurrency::task<std::vector<std::pair<std::wstring, size_t>>> FindCommonWords(const std::vector<std::wstring>& words, size_t min_length, size_t count);

    // Shows the most common words on the UI.
    void ShowResults(const std::vector<std::pair<std::wstring, size_t>>& commonWords);

将以下 using 语句添加到 MainPage.cpp。

using namespace concurrency;
using namespace std;
using namespace Windows::Storage;
using namespace Windows::Storage::Streams;

在 MainPage.cpp 中,实现 MainPage::MakeWordList、 MainPage::FindCommonWords和 MainPage::ShowResults 方法。 MainPage::MakeWordList 和 MainPage::FindCommonWords 执行计算密集型操作。 MainPage::ShowResults 方法在 UI 中显示计算的结果。

// Splits the provided text string into individual words.
task<vector<wstring>> MainPage::MakeWordList(String^ text)
{
    return create_task([text]() -> vector<wstring>
    {
        vector<wstring> words;

        // Add continuous sequences of alphanumeric characters to the string vector.
        wstring current_word;
        for (wchar_t ch : text)
        {
            if (!iswalnum(ch))
            {
                if (current_word.length() > 0)
                {
                    words.push_back(current_word);
                    current_word.clear();
                }
            }
            else
            {
                current_word += ch;
            }
        }

        return words;
    });
}

// Finds the most common words that are at least the provided minimum length.
task<vector<pair<wstring, size_t>>> MainPage::FindCommonWords(const vector<wstring>& words, size_t min_length, size_t count)
{
    return create_task([words, min_length, count]() -> vector<pair<wstring, size_t>>
    {
        typedef pair<wstring, size_t> pair;

        // Counts the occurrences of each word.
        concurrent_unordered_map<wstring, size_t> counts;

        parallel_for_each(begin(words), end(words), [&counts, min_length](const wstring& word)
        {
            // Increment the count of words that are at least the minimum length. 
            if (word.length() >= min_length)
            {
                // Increment the count.
                InterlockedIncrement(&counts[word]);
            }
        });

        // Copy the contents of the map to a vector and sort the vector by the number of occurrences of each word.
        vector<pair> wordvector;
        copy(begin(counts), end(counts), back_inserter(wordvector));

        sort(begin(wordvector), end(wordvector), [](const pair& x, const pair& y)
        {
            return x.second > y.second;
        });

        size_t size = min(wordvector.size(), count);
        wordvector.erase(begin(wordvector) + size, end(wordvector));

        return wordvector;
    });
}

// Shows the most common words on the UI. 
void MainPage::ShowResults(const vector<pair<wstring, size_t>>& commonWords)
{
    wstringstream ss;
    ss << "The most common words that have five or more letters are:";
    for (auto commonWord : commonWords)
    {
        ss << endl << commonWord.first << L" (" << commonWord.second << L')';
    }

    // Update the UI.
    Results->Text = ref new String(ss.str().c_str());
}

修改 MainPage 构造函数,以创建一个在 UI 中显示荷马的 伊利亚特 一书中常见单词的延续任务链。 前两个延续任务会将文本拆分为单个词并查找常见词,这会非常耗时,因此将其显式设置为在后台运行。 最终延续任务(即更新 UI)不指定延续上下文,因此遵循单元线程处理规则。

MainPage::MainPage()
{
    InitializeComponent();

    // To run this example, save the contents of http://www.gutenberg.org/files/6130/6130-0.txt to your Documents folder.
    // Name the file "The Iliad.txt" and save it under UTF-8 encoding.

    // Enable the progress ring.
    Progress->IsActive = true;

    // Find the most common words in the book "The Iliad".

    // Get the file.
    create_task(KnownFolders::DocumentsLibrary->GetFileAsync("The Iliad.txt")).then([](StorageFile^ file)
    {
        // Read the file text.
        return FileIO::ReadTextAsync(file, UnicodeEncoding::Utf8);

        // By default, all continuations from a Windows Runtime async operation run on the 
        // thread that calls task.then. Specify use_arbitrary to run this continuation 
        // on a background thread.
    }, task_continuation_context::use_arbitrary()).then([this](String^ file)
    {
        // Create a word list from the text.
        return MakeWordList(file);

        // By default, all continuations from a Windows Runtime async operation run on the 
        // thread that calls task.then. Specify use_arbitrary to run this continuation 
        // on a background thread.
    }, task_continuation_context::use_arbitrary()).then([this](vector<wstring> words)
    {
        // Find the most common words.
        return FindCommonWords(words, 5, 9);

        // By default, all continuations from a Windows Runtime async operation run on the 
        // thread that calls task.then. Specify use_arbitrary to run this continuation 
        // on a background thread.
    }, task_continuation_context::use_arbitrary()).then([this](vector<pair<wstring, size_t>> commonWords)
    {
        // Stop the progress ring.
        Progress->IsActive = false;

        // Show the results.
        ShowResults(commonWords);

        // We don't specify a continuation context here because we want the continuation 
        // to run on the STA thread.
    });
}

此示例演示了如何指定执行上下文以及如何构成延续链。 回想一下,从异步操作创建的任务默认情况下在调用了 task::then的单元上运行其延续。 因此,此示例使用 task_continuation_context::use_arbitrary 来指定不涉及 UI 的操作在后台线程上执行。 

 下图显示 CommonWords 应用的结果。

在此示例中,可以支持取消操作,因为支持 create_async 的 task 对象使用了隐式取消标记。 如果您的任务需要以协作方式响应取消,则请定义您的工作函数以采用 cancellation_token 对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2103063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

系统找不到指定的文件怎么解决?

把U盘插在电脑上&#xff0c;当我打开U盘中的文件时&#xff0c;弹窗提示系统找不到指定的文件&#xff0c;这是什么情况&#xff1f;有谁遇到过吗&#xff1f;大家有没有解决办法&#xff1f; 这个问题可能大家并不陌生&#xff0c;可能也曾遇到过&#xff0c;造成问题出现的原…

DriveLM的baseline复现

DriveLM是一篇很有意思的工作&#xff0c;把自动驾驶跟MLLM结合到一起了&#xff0c;实现端到端的感知or决策规划。 Repo&#xff1a;https://github.com/OpenDriveLab/DriveLM 该工作是基于nuScenes数据集做的&#xff0c;官方paper里给出了数据的具体构建方式&#xff0c;感…

云计算之ECS

目录 一、ECS云服务器 1.1 ECS的构成 1.2 ECS的实例规格 1.3 镜像 1.4 磁盘 1.5 安全组 1.6 网络 1.7 产品结构 二、块存储介绍 2.1 快存储定义 2.2 块存储性能指标 2.3 快存储常用操作-云盘扩容 2.4 块存储常见问题 三、快照介绍 3.1 快照定义 3.2 快照常见问题…

《python语言程序设计》第8章第12题生物信息:找出基因,生物学家使用字母A C T和G构成字符2串建模一个基因组(下)

一、上一个版本 抱歉各位兄弟我感觉这道题我现在的能力有限,不纠结了跳过去.等第3刷的时候解决吧. 可能彼岸就在眼前,但是我累了.等下次吧 这个版本中div_text函数已经可以很好的划分字符串了 但是我发现了一个问题.它间隔字符效果如下 genome_text TTATGTTTTAAGGATGGGGCGTTAG…

CSS - 搜索框小动效

点击搜索框动画变长&#xff0c;搜索框有内容不变&#xff0c;无内容失去焦点&#xff0c;变回原来模样。<div :class"type true ? s_r_z : s_r" click"onChange"><div class"input_s"><input blur"handleBlur" v-mo…

QTC++联合编程之解决代码语句块折叠并中文注释代码块

目录&#xff1a; 一&#xff0c;前言二&#xff0c;解决方法2.1直接折叠代码段落&#xff0c;不命名2.2折叠代码段落并注释&#xff08;中/英文&#xff09;命名2.3使用模板 三&#xff0c;参考文章 一&#xff0c;前言 如果从C#或者从其他语言学习过&#xff0c;一定会感叹ID…

Android实习面经整理第一篇

蔚来Android实习面经 一面(2024/3/11 35min) 自我介绍聊我的本专业说一说MVP架构,MVVM架构 MVP:V层持有P层,用户点击View,把数据发给P层,P层持有M层,然后P层把V层的数据发给M层获取其他数据,最后M层获取完数据后把数据还给P层,更新V层。P层也有V层的引用。MVVM:V层…

使用ElementUI + Vue框架实现学生管理系统前端页面设计

目录 一.什么是ElementUI&#xff1f; 二.使用ElementUI和Vue-cli搭建前端页面 三.具体步骤 1.创建vue-cli项目 2.分析 3.创建组件 四.总结 一.什么是ElementUI&#xff1f; ElementUI是一种网站快速成型工具&#xff0c;一套为开发者&#xff0c;设计师准备的基于Vue2.…

江协科技stm32————11-4 SPI通信协议

目录 SPI外设简介 SPI框图 波特率控制 SPE&#xff08;SPI使能&#xff09; 配置主从模式 四种模式的选择 发送和接收数据缓冲区状态 I2C基本结构 1. SPI模式选择 2. 时钟极性和相位&#xff08;CPOL和CPHA&#xff09; 3. 波特率设置 4. 数据帧格式 5. NSS引脚管…

Steam游戏截图方法

Steam游戏截图方法 截图快捷键 Steam游戏自带截图功能&#xff0c;在游戏中无需复杂的快捷键&#xff0c;仅需按下F12快捷键便可立即截图&#xff0c;官方说明如下。下文介绍使用方法。 查看截图 退出游戏后&#xff0c;在Steam界面点击查看 - 截图&#xff0c;即可查看截…

AndroidLogger 适配好了,但没法上架

看到有网友还在用之前的 AndroidLogger 版本&#xff0c;让我感动再次花了 2个月适配新的Notepad&#xff0c;总算搞完了&#xff0c;但是Notepad作者反了&#xff0c;我没法上架啊。 演示视频地址&#xff1a; Notepad安卓日志插件&#xff0c;支持文件管理和截屏&#xff0c…

无需前端技能:如何使用 Amis 框架简化页面开发

Amis 是一个由百度开源的前端低代码框架&#xff0c;它允许开发者通过 JSON 配置文件来快速生成各种后台管理页面。Amis 的设计理念是通过配置而非编码来实现页面的构建&#xff0c;这使得即使是不熟悉前端技术的开发者也能快速上手。Amis 提供了丰富的组件库和模板&#xff0c…

Mqtt消费端实现的几种方式

此处测试的mqtt的Broker是使用的EMQX 5.7.1&#xff0c;可移步至https://blog.csdn.net/tiantang_1986/article/details/140443513查看详细介绍 一、方式1 添加必要的依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spr…

蒸馏之道:如何提取白酒中的精华?

在白酒的酿造过程中&#xff0c;蒸馏是一道至关重要的工序&#xff0c;它如同一位技艺精细的炼金术士&#xff0c;将原料中的精华提炼出来&#xff0c;凝聚成滴滴琼浆。今天&#xff0c;我们就来探寻这蒸馏之道&#xff0c;看看豪迈白酒&#xff08;HOMANLISM&#xff09;是如何…

Linux 学习之路 - 信号的保存

前面已经介绍过信号的产生&#xff0c;本文将继续介绍信号的保存与处理。 1、上篇文章的遗留问题 从上篇文章(Linux学习之路 -- 信号概念 && 信号的产生-CSDN博客)中&#xff0c;其实还遗留了一些问题。OS在接受到信号后&#xff0c;大部分的进程的处理方式都是终止进…

合宙低功耗4G模组Air780E——产品规格书

Air780E 是合宙通信推出的 LTE Cat.1 bis通信模块&#xff1b; 采用移芯EC618平台&#xff0c;支持 LTE 3GPP Rel.13 技术。 Air780E特点和优势总结如下&#xff1a; 全网通兼容性&#xff1a; 作为4G全网通模块&#xff0c;兼容不同运营商网络&#xff0c;包括但不限于移动、…

【C++ Primer Plus习题】10.1

问题: 解答: main.cpp #include <iostream> #include "BankAccount.h" using namespace std;int main() {BankAccount BA1("韩立","韩跑跑",1);BA1.get_info();BankAccount BA;BA.init_account("姚国林", "amdin", 1…

国际化产品经理的挑战与机遇:跨文化产品管理的探索

全球化背景下的产品管理变革 在当今全球化的背景下&#xff0c;科技的进步和通信技术的普及&#xff0c;使得世界变得更加紧密相连。产品不再仅仅局限于单一市场&#xff0c;而是面向全球用户&#xff0c;这对产品经理提出了新的挑战与机遇。跨文化的产品管理要求产品经理不仅…

09-03 周二 ansible部署和节点管理过程

09-03 周二 ansible部署和节点管理过程 时间版本修改人描述2024年9月3日10:08:58V0.1宋全恒新建文档&#xff0c; 简介 首先要找一个跳板机&#xff0c;来确保所有的机器都可以访问。然后我们围绕ansible来搭建环境&#xff0c;方便一键执行所有的命令&#xff0c;主要的任务是…

通信算法之232: 无线发射功率和信号强度,常用单位dB、dBm、dBi和dBd介绍

[转载] 无线功率和信号强度的基本概念 在无线网络中&#xff0c;使用AP设备和天线来实现有线和无线信号互相转换。如下图所示&#xff1a; 有线网络侧的数据从AP设备的有线接口进入AP后&#xff0c;经AP处理为射频信号&#xff0c;从AP的发送端&#xff08;TX&#xff09;经过…