0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

C++/WinRTでUWPその7 非同期操作IAsyncAction/co_await

Last updated at Posted at 2021-03-12

#1.今回やること
・重い処理をしても、止まったり動かなくなったりしないUWPアプリを作成します。
・非同期関数(IAsyncAction)上で「co_await ...」を呼び出すことにより、バックグラウンドで処理させたり、スレッドプールへ放り込んだりして、重い処理をしている間も反応させましょう、と言うことをやります。重い処理は今回は「Sleep」に頑張ってもらいました。
C++/WinRT を使用した同時実行操作と非同期操作の一部の説明です。私の場合は、読んでもいきなりSyndicationClientとか知らんがな!ちゃんと理解できるように説明しやがれ!と思いつつ今に至ると。

##1-1. WinRTの非同期関数
①IAsyncAction:結果を返さない+進行状況を報告しない
②IAsyncActionWithProgress:結果を返さない+進行状況を報告する
③IAsyncOperation:結果を返す+進行状況を報告しない
④IAsyncOperationWithProgress:結果を返す+進行状況を報告する
・WinRTの非同期関数は上記4つがあります。
・今回は一番簡単な①を使用します。複雑なものは慣れてからやればいいのです。いきなり難しいものをやると挫折しますからね。

#2. 雛型の作成
##2-1. xamlの作成
・名前は「async_1」にして、余計なボタン等を削除して、見た目はこんな感じにしました。
・まだイベントハンドラは実装していません。

MainPage.xaml(変更後)
<Page
    x:Class="async_1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:async_1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="0">
            <Button x:Name="syncButton" Margin="5,5,5,5" Width="300" Height="100" Content="何も考えない" FontSize="24" ></Button>
            <TextBox x:Name="syncText" Margin="5,5,5,5" Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="1">
            <Button x:Name="asyncButton1" Margin="5,5,5,5" Width="300" Height="100" Content="非同期1" FontSize="24" ></Button>
            <TextBox x:Name="ayncText1" Margin="5,5,5,5"  Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="2">
            <Button x:Name="asyncButton2" Margin="5,5,5,5" Width="300" Height="100" Content="非同期2" FontSize="24" ></Button>
            <TextBox x:Name="ayncText2" Margin="5,5,5,5"  Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="3">
            <Button x:Name="asyncButton3" Margin="5,5,5,5" Width="300" Height="100" Content="非同期3" FontSize="24" ></Button>
            <TextBox x:Name="ayncText3" Margin="5,5,5,5"  Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
    </Grid>
</Page>

6-1.png


##2-2. StringViewModelの作成 ・その4で作成した変更通知可能なStringViewModelを作成します。こんな感じ。今回は何回呼ばれたとかは付け足しません。
StringViewModel.idl(変更後)

namespace async_1
{
    [Windows.UI.Xaml.Data.Bindable]
    runtimeclass StringViewModel : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        StringViewModel();
        String DataString;
    }
}

StringViewModel.h(変更後)
#pragma once

#include "StringViewModel.g.h"

namespace winrt::async_1::implementation
{
    struct StringViewModel : StringViewModelT<StringViewModel>
    {
        StringViewModel();
        StringViewModel(const winrt::hstring value);

        void DataString(winrt::hstring const& value);
        winrt::hstring DataString();

        winrt::event_token PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
        void PropertyChanged(winrt::event_token const& token) noexcept;

    private:

        winrt::hstring m_DataString;
        winrt::event<Windows::UI::Xaml::Data::PropertyChangedEventHandler> m_propertyChanged;

    };
}

namespace winrt::async_1::factory_implementation
{
    struct StringViewModel : StringViewModelT<StringViewModel, implementation::StringViewModel>
    {
    };
}
StringViewModel.cpp(変更後)
#include "pch.h"
#include "StringViewModel.h"
#if __has_include("StringViewModel.g.cpp")
#include "StringViewModel.g.cpp"
#endif

namespace winrt::async_1::implementation
{
    StringViewModel::StringViewModel() : m_DataString(L"クリックしてないよ!")
    {
    }
    StringViewModel::StringViewModel(const winrt::hstring value)
    {
        m_DataString = value;
    }
    void StringViewModel::DataString(winrt::hstring const& value)
    {
        m_DataString = value;
        m_propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs{ L"DataString" });
    }
    winrt::hstring StringViewModel::DataString()
    {
        return m_DataString;
    }
    winrt::event_token StringViewModel::PropertyChanged(Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
    {
        return m_propertyChanged.add(handler);
    }
    void StringViewModel::PropertyChanged(winrt::event_token const& token) noexcept
    {
        m_propertyChanged.remove(token);
    }
}


##2-3. MainPageで各TextBoxとバインド ・テキストボックスが今回は4個あるので~~コピペが大活躍~~大変です。こんな感じで同期/非同期処理をする準備が整いました。
MainPage.idl(変更後)

import "StringViewModel.idl";

namespace async_1
{
    [default_interface]
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        StringViewModel SSync{ get; };
        StringViewModel SAsync1{ get; };
        StringViewModel SAsync2{ get; };
        StringViewModel SAsync3{ get; };
    }
}
MainPage.h(変更後)
#pragma once

#include "MainPage.g.h"
#include "StringViewModel.h"

namespace winrt::async_1::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        async_1::StringViewModel SSync();
        async_1::StringViewModel SAsync1();
        async_1::StringViewModel SAsync2();
        async_1::StringViewModel SAsync3();

    private:
        async_1::StringViewModel m_SSync{ nullptr };
        async_1::StringViewModel m_SAsync1{ nullptr };
        async_1::StringViewModel m_SAsync2{ nullptr };
        async_1::StringViewModel m_SAsync3{ nullptr };
    };
}

namespace winrt::async_1::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}
MainPage.cpp(変更後)
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

namespace winrt::async_1::implementation
{
    MainPage::MainPage()
    {
        m_SSync = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync1 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync2 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync3 = winrt::make<async_1::implementation::StringViewModel>();
            

        InitializeComponent();
    }
    async_1::StringViewModel MainPage::SSync()
    {
        return m_SSync;
    }
    async_1::StringViewModel MainPage::SAsync1()
    {
        return m_SAsync1;
    }
    async_1::StringViewModel MainPage::SAsync2()
    {
        return m_SAsync2;
    }
    async_1::StringViewModel MainPage::SAsync3()
    {
        return m_SAsync3;
    }
}
MainPage.xaml(変更後)
<Page
    x:Class="async_1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:async_1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="0">
            <Button Click="syncButton_Click" x:Name="syncButton" Margin="5,5,5,5" Width="300" Height="100" Content="何も考えない" FontSize="24" ></Button>
            <TextBox x:Name="syncText" Text="{x:Bind SSync.DataString, Mode=OneWay}" Margin="5,5,5,5" Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="1">
            <Button x:Name="asyncButton1" Margin="5,5,5,5" Width="300" Height="100" Content="非同期1" FontSize="24" ></Button>
            <TextBox x:Name="ayncText1" Text="{x:Bind SAsync1.DataString, Mode=OneWay}" Margin="5,5,5,5"  Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="2">
            <Button x:Name="asyncButton2" Margin="5,5,5,5" Width="300" Height="100" Content="非同期2" FontSize="24" ></Button>
            <TextBox x:Name="ayncText2" Text="{x:Bind SAsync2.DataString, Mode=OneWay}" Margin="5,5,5,5"  Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
        <StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="3">
            <Button x:Name="asyncButton3" Margin="5,5,5,5" Width="300" Height="100" Content="非同期3" FontSize="24" ></Button>
            <TextBox x:Name="ayncText3" Text="{x:Bind SAsync3.DataString, Mode=OneWay}" Margin="5,5,5,5"  Width="300" Height="200" FontSize="24" Background="Aqua"></TextBox>
        </StackPanel>
    </Grid>
</Page>

・すでにやったところですので簡単ですね。

#3. 何も考えない同期処理
・syncButtonになにも考えずに同期処理を追加します。

MainPage.cpp(変更後・追記部分のみ)
void winrt::async_1::implementation::MainPage::syncButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    for (int i = 1; i <= 5; ++i)
    {
        //1秒もかかる凄い重い処理だ!!
        Sleep(1000);

        std::wostringstream woss;
        woss << i;
        std::wstring mes = woss.str() + L"秒経過!";
        SSync().DataString(mes);
    }
}

・これでsyncButtonをクリックしても5秒間止まって、5秒後に5秒経過!と出てくるだけです。何も考えていないので当たり前ですね。
6-2.png



#4. 重い固まる部分はバックグランドで処理しよう
・ここから非同期操作を使用して固まらないようにしていきます。
・まずは重い部分をバックグラウンドで処理させます。やり方は簡単で
①winrt::Windows::Foundation::IAsyncAction 関数内で
②winrt::resume_background()とresume_foreground()で囲むだけです。
・ただし、②の呼び出し時に「co_await」キーワードが必要です。ではやってみましょう。

・Async_Background関数を追加し、asyncButton1にもイベントハンドラを追加してください。そしてイベントハンドラから呼び出しましょう。こんな感じで。

MainPage.h(変更後)

#pragma once

#include "MainPage.g.h"
#include "StringViewModel.h"

namespace winrt::async_1::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        async_1::StringViewModel SSync();
        async_1::StringViewModel SAsync1();
        async_1::StringViewModel SAsync2();
        async_1::StringViewModel SAsync3();

        //Async_BackGround関数追加
        winrt::Windows::Foundation::IAsyncAction Async_Background();

    private:
        async_1::StringViewModel m_SSync{ nullptr };
        async_1::StringViewModel m_SAsync1{ nullptr };
        async_1::StringViewModel m_SAsync2{ nullptr };
        async_1::StringViewModel m_SAsync3{ nullptr };
    public:
        void syncButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
        //asyncButton1のイベントハンドラも追加
        void asyncButton1_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
    };
}

namespace winrt::async_1::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}

・resume_foreground()を使うには#include <winrt/Windows.UI.Core.h>が必要なのでそれも追加してください。

MainPage.cpp(変更後)
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

#include <string>
#include <sstream>
#include <winrt/Windows.UI.Core.h>

namespace winrt::async_1::implementation
{
    MainPage::MainPage()
    {
        m_SSync = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync1 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync2 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync3 = winrt::make<async_1::implementation::StringViewModel>();
            

        InitializeComponent();
    }
    async_1::StringViewModel MainPage::SSync()
    {
        return m_SSync;
    }
    async_1::StringViewModel MainPage::SAsync1()
    {
        return m_SAsync1;
    }
    async_1::StringViewModel MainPage::SAsync2()
    {
        return m_SAsync2;
    }
    async_1::StringViewModel MainPage::SAsync3()
    {
        return m_SAsync3;
    }

    //追加したAsync_Background()はここですよ
    winrt::Windows::Foundation::IAsyncAction MainPage::Async_Background()
    {
        for (int i = 1; i <= 5; ++i)
        {
            //重い処理はバックグラウンドで!!
            co_await winrt::resume_background();

            //1秒もかかる凄い重い処理だ!!
            Sleep(1000);

            //重い処理が終わったらもどすぞ!!
            co_await winrt::resume_foreground(this->Dispatcher());

            std::wostringstream woss;
            woss << i;
            std::wstring mes = woss.str() + L"秒経過!";
            SAsync1().DataString(mes);
        }
    }
}


void winrt::async_1::implementation::MainPage::syncButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    for (int i = 1; i <= 5; ++i)
    {
        //1秒もかかる凄い重い処理だ!!
        Sleep(1000);

        std::wostringstream woss;
        woss << i;
        std::wstring mes = woss.str() + L"秒経過!";
        SSync().DataString(mes);
    }
}


void winrt::async_1::implementation::MainPage::asyncButton1_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    Async_Background();
}

・これでリビルド→実行してみてください。asyncButton1をクリックすると、固まらずにちゃんと動くでしょ。こんなに簡単に。
・IAsyncAction関数にメンバ変数があっても、メンバ関数であっても問題なく非同期にできるので凄く楽ちんです。
・WIN32/64APIやMFCで重い処理をするときは、別スレッドでやっていたのでメンバをstaticにしたりフレンド関数を定義したり、UIを変更するのにメッセージを・・・と凄く大変でしたが、こんな簡単に非同期で動くんです。xamlやバインドはいらないけどWin32APIにもこれ欲しい・・・
・詳しい説明はC++/WinRT でのより高度な同時実行操作と非同期操作で。

・さて、次はスレッドプールへ投げ入れます。6-3.png



#5. スレッドプールで非同期操作
・今度はasyncButton2のイベントハンドラとして追加します。
・これも簡単でRunAsync([&](winrt::Windows::Foundation::IAsyncAction const& workItem){})を呼んでラムダ式の中に記述するだけです。#include <winrt/Windows.System.Threading.Core.h>も必要です。早速。

MainPage.h(変更後)

#include "MainPage.g.h"
#include "StringViewModel.h"

namespace winrt::async_1::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        async_1::StringViewModel SSync();
        async_1::StringViewModel SAsync1();
        async_1::StringViewModel SAsync2();
        async_1::StringViewModel SAsync3();

        winrt::Windows::Foundation::IAsyncAction Async_Background();

        //Async_ThreadPool追加
        winrt::Windows::Foundation::IAsyncAction Async_ThreadPool();

    private:
        async_1::StringViewModel m_SSync{ nullptr };
        async_1::StringViewModel m_SAsync1{ nullptr };
        async_1::StringViewModel m_SAsync2{ nullptr };
        async_1::StringViewModel m_SAsync3{ nullptr };
    public:
        void syncButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
        void asyncButton1_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
        void asyncButton2_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
    };
}

namespace winrt::async_1::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}
MainPage.cpp(変更後)
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

#include <string>
#include <sstream>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.System.Threading.Core.h>

namespace winrt::async_1::implementation
{
    MainPage::MainPage()
    {
        m_SSync = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync1 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync2 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync3 = winrt::make<async_1::implementation::StringViewModel>();
            

        InitializeComponent();
    }
    async_1::StringViewModel MainPage::SSync()
    {
        return m_SSync;
    }
    async_1::StringViewModel MainPage::SAsync1()
    {
        return m_SAsync1;
    }
    async_1::StringViewModel MainPage::SAsync2()
    {
        return m_SAsync2;
    }
    async_1::StringViewModel MainPage::SAsync3()
    {
        return m_SAsync3;
    }

    winrt::Windows::Foundation::IAsyncAction MainPage::Async_Background()
    {
        for (int i = 1; i <= 5; ++i)
        {
            //重い処理はバックグラウンドで!!
            co_await winrt::resume_background();

            //1秒もかかる凄い重い処理だ!!
            Sleep(1000);

            //重い処理が終わったらもどすぞ!!
            co_await winrt::resume_foreground(this->Dispatcher());

            std::wostringstream woss;
            woss << i;
            std::wstring mes = woss.str() + L"秒経過!";
            SAsync1().DataString(mes);
        }
    }

    //Async_ThreadPool()はここ
    winrt::Windows::Foundation::IAsyncAction MainPage::Async_ThreadPool()
    {
        for (int i = 1; i <= 5; ++i)
        {
            //重い処理はスレッドプールで
            co_await winrt::Windows::System::Threading::ThreadPool::RunAsync([&](winrt::Windows::Foundation::IAsyncAction const& workItem)
                {
                    //1秒もかかる凄い重い処理だ!!
                    Sleep(1000);
                });

            std::wostringstream woss;
            woss << i;
            std::wstring mes = woss.str() + L"秒経過!";
            SAsync2().DataString(mes);
        }
    }
}


void winrt::async_1::implementation::MainPage::syncButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    for (int i = 1; i <= 5; ++i)
    {
        //1秒もかかる凄い重い処理だ!!
        Sleep(1000);

        std::wostringstream woss;
        woss << i;
        std::wstring mes = woss.str() + L"秒経過!";
        SSync().DataString(mes);
    }
}


void winrt::async_1::implementation::MainPage::asyncButton1_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    Async_Background();
}


void winrt::async_1::implementation::MainPage::asyncButton2_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    Async_ThreadPool();
}

6-5.png

・これでスレッドプールで処理するのも簡単とわかってもらえたと思います。詳しくはスレッド プールへの作業項目の送信
・イベントハンドラから非同期関数を呼んでいましたが、最後はイベントハンドラ自身をIAsyncActionにしてco_awaitを記述できるか試してみましょう。



#6. イベントハンドラで非同期操作
・やることは簡単で、asyncButton3にイベントハンドラを追加します。
・追加した後に戻り値の型をwinrt::Windows::Foundation::IAsyncActionへ変更すれば良いだけです。
・やってみましょう。

MainPage.h(変更後)
#pragma once

#include "MainPage.g.h"
#include "StringViewModel.h"

namespace winrt::async_1::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        async_1::StringViewModel SSync();
        async_1::StringViewModel SAsync1();
        async_1::StringViewModel SAsync2();
        async_1::StringViewModel SAsync3();

        winrt::Windows::Foundation::IAsyncAction Async_Background();
        winrt::Windows::Foundation::IAsyncAction Async_ThreadPool();

    private:
        async_1::StringViewModel m_SSync{ nullptr };
        async_1::StringViewModel m_SAsync1{ nullptr };
        async_1::StringViewModel m_SAsync2{ nullptr };
        async_1::StringViewModel m_SAsync3{ nullptr };
    public:
        void syncButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
        void asyncButton1_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
        void asyncButton2_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
        //ここ追加した後、型を変更しました。
        winrt::Windows::Foundation::IAsyncAction asyncButton3_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
    };
}

namespace winrt::async_1::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}
MainPage.cpp(変更後)
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"

using namespace winrt;
using namespace Windows::UI::Xaml;

#include <string>
#include <sstream>
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.System.Threading.Core.h>

namespace winrt::async_1::implementation
{
    MainPage::MainPage()
    {
        m_SSync = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync1 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync2 = winrt::make<async_1::implementation::StringViewModel>();
        m_SAsync3 = winrt::make<async_1::implementation::StringViewModel>();
            

        InitializeComponent();
    }
    async_1::StringViewModel MainPage::SSync()
    {
        return m_SSync;
    }
    async_1::StringViewModel MainPage::SAsync1()
    {
        return m_SAsync1;
    }
    async_1::StringViewModel MainPage::SAsync2()
    {
        return m_SAsync2;
    }
    async_1::StringViewModel MainPage::SAsync3()
    {
        return m_SAsync3;
    }

    winrt::Windows::Foundation::IAsyncAction MainPage::Async_Background()
    {
        for (int i = 1; i <= 5; ++i)
        {
            //重い処理はバックグラウンドで!!
            co_await winrt::resume_background();

            //1秒もかかる凄い重い処理だ!!
            Sleep(1000);

            //重い処理が終わったらもどすぞ!!
            co_await winrt::resume_foreground(this->Dispatcher());

            std::wostringstream woss;
            woss << i;
            std::wstring mes = woss.str() + L"秒経過!";
            SAsync1().DataString(mes);
        }
    }

    winrt::Windows::Foundation::IAsyncAction MainPage::Async_ThreadPool()
    {
        for (int i = 1; i <= 5; ++i)
        {
            //重い処理はスレッドプールで
            co_await winrt::Windows::System::Threading::ThreadPool::RunAsync([&](winrt::Windows::Foundation::IAsyncAction const& workItem)
                {
                    //1秒もかかる凄い重い処理だ!!
                    Sleep(1000);
                });

            std::wostringstream woss;
            woss << i;
            std::wstring mes = woss.str() + L"秒経過!";
            SAsync2().DataString(mes);
        }
    }
}


void winrt::async_1::implementation::MainPage::syncButton_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    for (int i = 1; i <= 5; ++i)
    {
        //1秒もかかる凄い重い処理だ!!
        Sleep(1000);

        std::wostringstream woss;
        woss << i;
        std::wstring mes = woss.str() + L"秒経過!";
        SSync().DataString(mes);
    }
}


void winrt::async_1::implementation::MainPage::asyncButton1_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    Async_Background();
}


void winrt::async_1::implementation::MainPage::asyncButton2_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    Async_ThreadPool();
}

//ここ追加した後、型を変更しました。
winrt::Windows::Foundation::IAsyncAction winrt::async_1::implementation::MainPage::asyncButton3_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
{
    for (int i = 1; i <= 5; ++i)
    {
        //重い処理はスレッドプールで
        co_await winrt::Windows::System::Threading::ThreadPool::RunAsync([&](winrt::Windows::Foundation::IAsyncAction const& workItem)
            {
                //1秒もかかる凄い重い処理だ!!
                Sleep(1000);
            });

        std::wostringstream woss;
        woss << i;
        std::wstring mes = woss.str() + L"秒経過!";
        SAsync3().DataString(mes);
    }
}

・これも簡単ですね。非同期なんて恐るるに足らずです。
winRT APIを検索すると、~Asyncという非同期関数が大量に出てきます。この非同期関数も今回winrt::Windows::System::Threading::ThreadPool::RunAsyncを呼び出したと同じようにIAsyncActionから「co_await」をつけて呼び出せば非同期に使用できます。

githubもおいておきます。

・今回使用しなかった1-1の
②④については、C++/WinRT でのより高度な同時実行操作と非同期操作の最後の方に書いてあったり無かったりしています。
③についてはC++/WinRT の強参照と弱参照に書いてあったりします。

・今回までで、
①xamlによるUIの編集
②バインドによるコントロールの操作
③非同期操作
というwinRT APIを使う上での基礎が終了しました。これでmicrosoft/windows-universal-samplseにあるサンプルも、もう簡単に?読めるはずなので読んで使ってみてください。

・次はWinRT APIを使用して何か作ってみます。まずは何をしようかなぁ・・・

もくじへ

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?