首页 > 系统相关 >windows C++ 并行编程-并发和UWP(三)

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

时间:2024-09-04 20:22:13浏览次数:6  
标签:task windows continuation UWP C++ MainPage 线程 words UI

控制执行线程

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 对象。

标签:task,windows,continuation,UWP,C++,MainPage,线程,words,UI
From: https://blog.csdn.net/m0_72813396/article/details/141539316

相关文章

  • windows C++ 并行编程-并发和UWP(一)
    本文介绍当在通用Windows运行时(UWP)应用中使用任务类生成基于Windows线程池的异步操作时要谨记的一些要点。异步编程的使用是Windows运行时应用模型中的关键组成部分,因为它能使应用保持对用户输入的响应。可以启动长期运行的任务,而不必阻止UI线程,并且可以在以后接......
  • linux C++基于共享内存的同步机制
    无缘进程间同步,本来打算使用有名信号量进行同步,但是有名信号量的初始化会受进程启动顺序影响,故使用共享内存进行封装,封装后的使用方法类似二值信号量,代码如下:1#include<sys/ipc.h>//ipc:inter-processcommunication进程通信2#include<sys/shm.h>//shm:shareme......
  • 坐牢第三十五天(c++)
    一.作业1.使用模版类自定义栈代码:#include<iostream>usingnamespacestd;template<typenameT>//封装一个栈classstcak{private:T*data;//intmax_size;//最大容量inttop;//下标public://无参构造函数stcak();//......
  • 2024.9.4C++作业
    #include<iostream>#include<string>usingnamespacestd;classHuman{public:Human(){name="Unknown";age=0;}Human(stringn,inta){name=n;age=a;}~Hu......
  • 2024.9.3C++
    自行实现Mystring类#include<iostream>#include<cstring>usingnamespacestd;classmystring{public:mystring(){len=0;str=nullptr;}mystring(constchar*s){len=strlen(s);str=ne......
  • 2024.9.2C++作业
    自行实现一个Mystring类#include<iostream>#include<cstring>usingnamespacestd;classmystring{public:mystring(){len=0;str=nullptr;}mystring(constchar*s){len=strlen(s);str=n......
  • C++基础之杂项
    目录思维导图:学习内容:1. Lambda表达式1.1基本概念1.2定义格式1.3常用情况二、异常处理2.1什么是异常处理2.2何时使用异常处理2.3异常处理的格式2.4异常实例2.5构造和析构中的异常 2.6系统提供异常类 三、C++中文件操作3.1文件流对象的介绍3.2关......
  • Windows 一顿操作倒逼用户!Linux 桌面坐收渔利,市场份额攀至新高峰
    根据StatCounter的最新数据,截至2024年7月,Linux在全球桌面操作系统的市场份额已达到4.45%。虽然这一百分比对于那些不熟悉操作系统领域的人来说可能看起来很小,但它对Linux及其专注的社区来说是一个重要的里程碑。更令人振奋的是Linux采用率的上升趋势。图片1.稳定进步......
  • Codeforces Round 971 (Div. 4) ABCD题详细题解(C++,Python)
    前言:    本文为CodeforcesRound971(Div.4)ABCD题的题解,包含C++,Python语言描述,觉得有帮助或者写的不错可以点个赞    比赛打了没一半突然unrated了就不是很想继续写了,早起写个题解    (之前的div3也没复盘,哎真菜)目录题A:题目大意和解题......
  • AtCoder Beginner Contest 369 题ABCD详细题解--包含解题思路和两种语言(C++,Python)
    前言:    本文为AtCoderBeginnerContest369题ABCD详细题解,包括题目大意,详细的解题思路和两种语言描述,觉的有帮助或者写的不错可以点个赞几天前的比赛拖的有点久了比赛题目连接:Tasks-AtCoderBeginnerContest369目录题A:题目大意和解题思路:代码(C++):......