読者です 読者をやめる 読者になる 読者になる

がりらぼ

WindowsRuntimeの応援ブログ

C++/CXの非同期処理簡単なサンプル

ちょっとC++/CXでDirectXをいじるときにTask型の非同期処理のやり方がわからなくてこまったので

基本的にC#などではasync awaitをすることで非同期処理を同期処理のように記述することができますがC++/CXにはasync awaitはありません。
ですのでtask型を作ってタスクチェーンという方法で連続する非同期処理を書きます。

WindowsRuntime非同期APIを呼び出す場合

~Asyncなど、WindowsRuntimeに最初から用意されている非同期メソッドを呼び出す場合、C#ならこう記述します。

C#

private async void btn1_Click(object sender, RoutedEventArgs e)
{
//using Windows.UI.Popups;

    MessageDialog dialog1 = new MessageDialog("hoge1");
    await dialog1.ShowAsync();

    MessageDialog dialog2 = new MessageDialog("hoge2");
    await dialog2.ShowAsync();

    
}

メソッドの戻り値の前にasyncを書いて非同期処理のところにawaitを書くだけですね
これをC++/CXで書くとこんな感じ

まずppltask.hをインクルードします。
名前空間はMessageDialogをだすためにWindows::UI::Popupsを、ppltasks内のクラスを実行するためにconcurrencyを指定します。

#include <ppltasks.h>

using namespace Windows::UI::Popups;
using namespace concurrency;

基本的に非同期メソッドをcreate_taskメソッドの引数に渡します。 戻り値として受け取ったtask型のthenメソッドの引数にラムダ式で処理を記述すると、その非同期処理が終わった後にラムダ式内が呼ばれます。

C++

void App13::MainPage::btn1_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    MessageDialog^ dialog1 = ref new MessageDialog("hoge1");
    task<IUICommand^> dialog1AsyncTask = create_task(dialog1->ShowAsync());
    
    dialog1AsyncTask.then([this](IUICommand^ command){
        MessageDialog^ dialog2 = ref new MessageDialog("hoge2");
        return dialog2->ShowAsync();
    });
    
}

独自の非同期メソッドを定義する場合

C#の場合独自の非同期メソッドを作ろうと思ったらTask.Runメソッドで作成します。

C#

//戻り値を返す場合
IAsyncOperation<int> GetNumAsync()
{
    return Task.Run(() =>
    {
        int i = 0;
        for (i = 0; i < 1000; i++)
        {
            i++;
        }
        return i;
    }).AsAsyncOperation<int>();
}
//戻り値を返さない場合
IAsyncAction CalcNumAsync()
{
    return Task.Run(() =>
    {
        int i = 0;
        for (i = 0; i < 1000; i++)
        {
            i++;
        }
        
    }).AsAsyncAction();
}

これをC++で書くとこんな感じ Task.Runはcreate_asyncメソッドで代用します。

C++

IAsyncOperation<int>^ GetNumAsync()
{
    return create_async([](){
        int i = 0;
        for (i = 0; i < 1000; i++){
            i++;
        }
        return i;
    });
}

IAsyncAction^ CalcNumAsync(){
    return create_async([](){
        int i = 0;
        for (int i = 0; i < 1000; i++){
            i++;
        }
        
    });
}

実行するときは、C#はasync await、C++の場合はcreate_taskでおkです。

C#

private async void btn2_Click(object sender, RoutedEventArgs e)
{
    await GetNumAsync();
    await CalcNumAsync();
}

C++

void App13::MainPage::btn2_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    task<int> getNumTask=create_task(GetNumAsync());
    getNumTask.then([](int num){
        task<void> calcNumtask=create_task(CalcNumAsync());
    });
}

C++/CXにもasync awaitほしい...

C++ での非同期プログラミング (Windows ランタイム アプリ) - Windows app development