C++ における Windows ストア アプリ用の非同期操作の作成
このドキュメントでは Windows ストア アプリケーションの非同期操作を生成するには、同時実行ランタイムを使用することに留意しては、キーの一部を示します。
非同期プログラミングの使用は、ユーザー入力に依存状態に apps を使用することに Windows ストア アプリケーション モデルの主要部分です。UI スレッドをブロック時間のかかるタスクをタスクの開始後に結果を表示できます。また、タスクをキャンセル、バックグラウンドで実行するタスクとして進行状況の通知を受け取ることができます。ドキュメント C++ で使用した非同期プログラミング は Windows ストア の apps を作成して Visual C++ で使用できる非同期パターンの概要を示します。どのように Windows ランタイム の非同期操作のチェーンを実行し、作成する方法をそのドキュメントに教えられています。ここでは Windows ランタイム の別のコンポーネントで、非同期処理を実行する方法を制御する方法を生成するには、同時実行ランタイムを使用する方法を実行できる非同期操作について説明します。また、C++ を使用して Hilo の非同期操作 Windows ストア、アプリケーションと XAML の実装により、同時実行ランタイムを使用したかについては読み取ること Hilo (C++ および XAML を使用して Windows ストア apps) 単一のプログラミング パターンとツールヒント を検討してください。
[!メモ]
Windows ストア アプリケーションで [Parallel Patterns Library] (PPL) と 非同期エージェント ライブラリ を使用できます。ただし、タスク スケジューラとリソース マネージャーを使用できません。ここでは、同時実行ランタイムが Windows ストア アプリケーションにのみ使用でき、デスクトップ アプリケーションに提供する追加機能を示します。
キー
(C++ 以外の言語で可能) で使用する記述する他のコンポーネント非同期操作の作成に concurrency::create_async を使用します。
、非同期操作を呼び出すコンポーネントの通知に進行状況を報告するために concurrency::progress_reporter を使用します。
内部非同期操作がキャンセルできるようにするには、キャンセル トークンを使用します。
create_async の関数の動作は、に渡される処理関数の戻り値の型によって異なります。create_asyncを呼び出したコンテキストで同期的にタスクの task<T> (または) **task<void>**実行作業を返す関数。任意のコンテキスト T か void の実行作業を返す関数。
順次実行タスクのチェーンを作成するには concurrency::task::then のメソッドを使用できます。Windows ストア アプリケーションでは、タスクの継続の既定のコンテキストは、そのタスクがジェネリックかによって異なります。タスクとタスクのコンストラクターに非同期アクションを非同期アクションを返すラムダ式を渡すことを渡すことによって作成されている場合は、そのタスクの継続の既定のコンテキストは、現在のコンテキストです。タスクは非同期のアクションから構築、ランダム コンテキストはタスクの継続で既定で使用されます。concurrency::task_continuation_context のクラスとの既定のコンテキストをオーバーライドできます。
目次
非同期操作の作成
例: C ++. Windows のランタイム コンポーネントの作成
スレッド実行の制御
例: C++ および XAML の Windows ストア App の実行の制御
非同期操作の作成
並列パターン ライブラリ (PPL) でバックグラウンド タスクを、前のタスクが完了すると実行される追加のタスクを定義するタスクや継続のモデルを使用できます。この機能は concurrency::task のクラスによって提供されます。このモデルと task のクラスの詳細については、タスクの並列化 (同時実行ランタイム)"を参照してください。
Windows ランタイム は、特殊なオペレーティング システムの環境でのみ実行 Windows ストア の apps を作成するために使用できるプログラミング インターフェイスです。承認されるこのような apps の使用は Windows ストアから、データ型、およびデバイス機能し、配布されます。Windows ランタイム は ABI (ABI) によって表されます。ABI は Windows ランタイム API を Visual C++ などのプログラミング言語で使用できるようにする基のバイナリ コントラクトです。
Windows ランタイムを使用して、さまざまなプログラミング言語の最適な機能を使用し、1 種類のアプリケーションにまとめることができます。たとえば、JavaScript の UI を作成して、C ++.のコンポーネントが使い果たされるアプリケーションのロジックを実行する場合があります。バックグラウンドでこれらの使い果たされる操作を実行する機能は、UI の応答性を保つためのキー ファクタです。task のクラスが C++ 固有であるため、渡すために記述されている可能性もある) と非同期操作を他のコンポーネント (C++ 以外の言語で Windows ランタイム インターフェイスを使用する必要があります。Windows ランタイム は、非同期操作を表すために使用できる 4 種類のインターフェイスが用意されています:
Windows::Foundation::IAsyncAction
非同期アクションを表します。Windows::Foundation::IAsyncActionWithProgress<TProgress>
の進行状況レポートは、非同期アクションを表します。Windows::Foundation::IAsyncOperation<TResult>
結果を返す非同期操作を表します。Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>
結果とレポートには非同期操作の進行状況を表します。
アクション の概念は、非同期タスクが値を生成しないことを意味します (voidを返す) 関数について検討します。操作 の概念は、非同期タスクが値を生成することを意味します。進行状況 の概念はタスクを呼び出し元に進行状況を報告できることを意味します。JavaScript、.NET Framework および Visual C++ は、それぞれ ABI の境界を越えて使用するこれらのインターフェイスのインスタンスを作成する独自の方法を提供します。Visual C++ では、同時実行ランタイムは concurrency::create_async 関数を提供します。この関数は、タスクの完了を表す操作または Windows ランタイム の非同期アクションを作成します。create_async の関数は、通常、処理関数 (ラムダ式) をあり、内部的に task の Windows ランタイム の 4 種類の非同期インターフェイスの 1 つがでタスクを作成およびオブジェクトをラップします。
[!メモ]
別の言語または Windows ランタイム の別のコンポーネントからアクセスできる機能を作成する必要がある場合にのみ create_async を使用します。操作は同じコンポーネントの C++ コードで生成、実行されることがわかっている場合に task のクラスを直接使用します。
create_async の戻り値の型は、引数の型によって決まります。たとえば、作業関数が値を返さないし、進行状況を報告する create_async は、IAsyncActionを返します。作業関数が値を返さないし、レポートが進行すると、create_async は IAsyncActionWithProgressを返します。進行状況をレポートするには、作業関数のパラメーターとして concurrency::progress_reporter のオブジェクトを提供します。進行状況をレポートする機能は、作業量が実行され、どのような量がまだ量を報告することができます (たとえば、パーセント)。また、使用できるようになったら結果を報告することができます。
IAsyncAction、IAsyncActionWithProgress<TProgress>、IAsyncOperation<TResult>と IAsyncActionOperationWithProgress<TProgress, TProgress> のインターフェイスは、非同期操作をキャンセルできるようにする Cancel のメソッドを提供します。task のクラスは、キャンセル トークンを使用します。作業を[キャンセル]にキャンセル トークンを使用すると、ランタイムはそのトークンをサブスクライブするな更新操作を開始しません。使用できる場合は。既にアクティブ キャンセル トークンを監視および停止するためです。この機構はドキュメント PPL における取り消し処理で詳しく説明します。2 とおりの方法で Windows ランタイムCancel のメソッドのタスクのキャンセルを接続できます。最初に、create_async に concurrency::cancellation_token のオブジェクトに取り込むために渡される処理関数を定義できます。Cancel のメソッドが呼び出されると、このキャンセル トークンは、キャンセル create_async の使用をサポートする通常のキャンセルの規則は、基になる task にオブジェクトを追加します。cancellation_token のオブジェクトを提供する、task の基になるオブジェクトは 1 を暗黙的に定義します。協調的に処理関数のキャンセルに応答する必要がある場合 cancellation_token のオブジェクトを定義します。セクション 例: C++ および XAML の Windows ストア App の実行の制御 例を Windows ランタイム カスタム C++ コンポーネントを使用すると、C と XAML Windows ストア アプリケーションでキャンセルを実行する方法を説明します。
注意 |
---|
タスクの継続のチェーンでは、concurrency::is_task_cancellation_requested が trueを返す状態を常に消去してから concurrency::cancel_current_task を呼び出します。cancel_current_taskを呼び出す代わりにすぐに制御を返す場合は、[キャンセル状態ではなく操作の完了状態への遷移。 |
次の表では、のアプリケーションの非同期操作を定義するために使用できる組み合わせを示します。
Windows ランタイム、このインターフェイスを作成するには |
create_asyncからこの型を返します。 |
暗黙のキャンセル トークンを使用するように、の処理関数にこれらのパラメーターの型を渡します。 |
明示的なキャンセル トークンを使用するように、の処理関数にこれらのパラメーターの型を渡します。 |
---|---|---|---|
IAsyncAction |
void または task<void> |
(なし) |
(cancellation_token) |
IAsyncActionWithProgress<TProgress> |
void または task<void> |
(progress_reporter) |
(progress_reporter, cancellation_token) |
IAsyncOperation<TResult> |
T または task<T> |
(なし) |
(cancellation_token) |
IAsyncActionOperationWithProgress<TProgress, TProgress> |
T または task<T> |
(progress_reporter) |
(progress_reporter, cancellation_token) |
create_async に関数を渡す処理関数から値または task のオブジェクトを返すことができます。これらの変更は異なる動作になります。値が返されたら、処理関数は task でバックグラウンド スレッドで実行できるようにラップされます。また、基になる task は、暗黙のキャンセル トークンを使用します。逆に task のオブジェクトを返した場合、処理関数は同期的に実行されます。したがって task のオブジェクトを返す場合は、の処理関数のすべてのかかる操作でも、アプリケーションが実行できるタスクとして認識状態に実行されることを確認します。また、基になる task は、暗黙のキャンセル トークンを使用しません。したがって create_asyncから task のオブジェクトを返す場合、キャンセルをサポートする必要がある場合、cancellation_token のオブジェクトを受け取るように処理関数を定義する必要があります。
次の例では Windows ランタイム の別のコンポーネントで使用できる IAsyncAction のオブジェクトを作成するさまざまな方法を示します。
// Creates an IAsyncAction object and uses an implicit cancellation token.
auto op1 = create_async([]
{
// Define work here.
});
// Creates an IAsyncAction object and uses no cancellation token.
auto op2 = create_async([]
{
return create_task([]
{
// Define work here.
});
});
// Creates an IAsyncAction object and uses an explicit cancellation token.
auto op3 = create_async([](cancellation_token ct)
{
// Define work here.
});
// Creates an IAsyncAction object that runs another task and also uses an explicit cancellation token.
auto op4 = create_async([](cancellation_token ct)
{
return create_task([ct]()
{
// Define work here.
});
});
[Top]
例: C ++. Windows のランタイム コンポーネントと、C からこれを実行して作成します
UI と C ++. Windows ランタイム コンポーネントの定義に集中型の計算を操作する XAML と、C を使用するアプリケーションを検討してください。特定の範囲で行番号を持つこの例では、C++ コンポーネントの計算は素数です。4 個の Windows ランタイム の非同期タスクの相違について説明し、[空のソリューション] を作成し、それを [Primes]と参照することによって、Visual Studio で開始します。ソリューションに [Windows ランタイム コンポーネント] のプロジェクトと PrimesLibraryと表示を追加します。生成された C++ ヘッダー ファイルに次のコードを追加します (この例では Class1.h に Primes.h の名前を変更したものです)。public の各メソッドは 4 個の非同期の 1 つがインターフェイスを定義します。値からオブジェクトを Windows::Foundation::Collections::IVector<int> 返すメソッド。完了している全体的な作業の割合を定義する進行状況により、の double の値を報告するメソッド。
#pragma once
namespace PrimesLibrary
{
public ref class Primes sealed
{
public:
Primes();
// Computes the numbers that are prime in the provided range and stores them in an internal variable.
Windows::Foundation::IAsyncAction^ ComputePrimesAsync(int first, int last);
// Computes the numbers that are prime in the provided range and stores them in an internal variable.
// This version also reports progress messages.
Windows::Foundation::IAsyncActionWithProgress<double>^ ComputePrimesWithProgressAsync(int first, int last);
// Gets the numbers that are prime in the provided range.
Windows::Foundation::IAsyncOperation<Windows::Foundation::Collections::IVector<int>^>^ GetPrimesAsync(int first, int last);
// Gets the numbers that are prime in the provided range. This version also reports progress messages.
Windows::Foundation::IAsyncOperationWithProgress<Windows::Foundation::Collections::IVector<int>^, double>^ GetPrimesWithProgressAsync(int first, int last);
};
}
[!メモ]
規則により、Windows ランタイム の非同期メソッドの名前に "Async" と正常に終了。
生成された C++ のソース ファイルに次のコードを追加します (この例では Class1.cpp に Primes.cpp の名前を変更したものです)。is_prime の関数は、入力が素数かどうかを判定します。残りのメソッドは Primes のクラスを実装します。create_async に対する各呼び出しは、呼び出すメソッドと互換性があるシグネチャを使用します。たとえば、Primes::ComputePrimesAsync が IAsyncActionを返すので、create_async に指定された処理関数は、値を返さないし、パラメーターとして progress_reporter のオブジェクトを受け取りません。
// PrimesLibrary.cpp
#include "pch.h"
#include "Primes.h"
#include <atomic>
#include <collection.h>
#include <ppltasks.h>
#include <concurrent_vector.h>
using namespace concurrency;
using namespace std;
using namespace Platform;
using namespace Platform::Collections;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace PrimesLibrary;
Primes::Primes()
{
}
// Determines whether the input value is prime.
bool is_prime(int n)
{
if (n < 2)
{
return false;
}
for (int i = 2; i < n; ++i)
{
if ((n % i) == 0)
{
return false;
}
}
return true;
}
// Adds the numbers that are prime in the provided range
// to the primes global variable.
IAsyncAction^ Primes::ComputePrimesAsync(int first, int last)
{
return create_async([this, first, last]
{
// Ensure that the input values are in range.
if (first < 0 || last < 0)
{
throw ref new InvalidArgumentException();
}
// Perform the computation in parallel.
parallel_for(first, last + 1, [this](int n)
{
if (is_prime(n))
{
// Perhaps store the value somewhere...
}
});
});
}
IAsyncActionWithProgress<double>^ Primes::ComputePrimesWithProgressAsync(int first, int last)
{
return create_async([first, last](progress_reporter<double> reporter)
{
// Ensure that the input values are in range.
if (first < 0 || last < 0)
{
throw ref new InvalidArgumentException();
}
// Perform the computation in parallel.
atomic<long> operation = 0;
long range = last - first + 1;
double lastPercent = 0.0;
parallel_for(first, last + 1, [&operation, range, &lastPercent, reporter](int n)
{
// Report progress message.
double progress = 100.0 * (++operation) / range;
if (progress >= lastPercent)
{
reporter.report(progress);
lastPercent += 1.0;
}
if (is_prime(n))
{
// Perhaps store the value somewhere...
}
});
reporter.report(100.0);
});
}
IAsyncOperation<IVector<int>^>^ Primes::GetPrimesAsync(int first, int last)
{
return create_async([this, first, last]() -> IVector<int>^
{
// Ensure that the input values are in range.
if (first < 0 || last < 0)
{
throw ref new InvalidArgumentException();
}
// Perform the computation in parallel.
concurrent_vector<int> primes;
parallel_for(first, last + 1, [this, &primes](int n)
{
// If the value is prime, add it to the global vector.
if (is_prime(n))
{
primes.push_back(n);
}
});
// Sort the results.
sort(begin(primes), end(primes), less<int>());
// Copy the results to an IVector object. The IVector
// interface makes collections of data available to other
// Windows Runtime components.
auto results = ref new Vector<int>();
for (int prime : primes)
{
results->Append(prime);
}
return results;
});
}
IAsyncOperationWithProgress<IVector<int>^, double>^ Primes::GetPrimesWithProgressAsync(int first, int last)
{
return create_async([this, first, last](progress_reporter<double> reporter) -> IVector<int>^
{
// Ensure that the input values are in range.
if (first < 0 || last < 0)
{
throw ref new InvalidArgumentException();
}
// Perform the computation in parallel.
concurrent_vector<int> primes;
long operation = 0;
long range = last - first + 1;
double lastPercent = 0.0;
parallel_for(first, last + 1, [&primes, &operation, range, &lastPercent, reporter](int n)
{
// Report progress message.
double progress = 100.0 * (++operation) / range;
if (progress >= lastPercent)
{
reporter.report(progress);
lastPercent += 1.0;
}
// If the value is prime, add it to the local vector.
if (is_prime(n))
{
primes.push_back(n);
}
});
reporter.report(100.0);
// Sort the results.
sort(begin(primes), end(primes), less<int>());
// Copy the results to an IVector object. The IVector
// interface makes collections of data available to other
// Windows Runtime components.
auto results = ref new Vector<int>();
for (int prime : primes)
{
results->Append(prime);
}
return results;
});
}
各メソッドは、最初に入力パラメーターは負であることを確認する検証を実行します。入力値が負の場合、メソッド Platform::InvalidArgumentExceptionはをスローします。エラー処理は、このセクションで後述します。
Windows ストア アプリケーションからこれらのメソッドを実装するには、Visual Studio ソリューションに 2 番目のプロジェクトを追加するには、Visual C# [Blue / Z] テンプレートを使用します。この例では、プロジェクト [Primes]を示します。次に、[Primes] のプロジェクトから、PrimesLibrary のプロジェクトへの参照を追加します。
MainPage.xaml に次のコードを追加します。このコードは、C++ コンポーネントと表示の結果を呼び出すために UI を定義します。
<Page
x:Class="Primes.MainPage"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Primes"
xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"/>
<ColumnDefinition Width="300"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="125"/>
<RowDefinition Height="125"/>
<RowDefinition Height="125"/>
</Grid.RowDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0">
<Button Name="b1" Click="computePrimes">Compute Primes</Button>
<TextBlock Name="tb1"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="0">
<Button Name="b2" Click="computePrimesWithProgress">Compute Primes with Progress</Button>
<ProgressBar Name="pb1" HorizontalAlignment="Left" Width="100"></ProgressBar>
<TextBlock Name="tb2"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="1">
<Button Name="b3" Click="getPrimes">Get Primes</Button>
<TextBlock Name="tb3"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="1">
<Button Name="b4" Click="getPrimesWithProgress">Get Primes with Progress</Button>
<ProgressBar Name="pb4" HorizontalAlignment="Left" Width="100"></ProgressBar>
<TextBlock Name="tb4"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="2">
<Button Name="b5" Click="getPrimesHandleErrors">Get Primes and Handle Errors</Button>
<ProgressBar Name="pb5" HorizontalAlignment="Left" Width="100"></ProgressBar>
<TextBlock Name="tb5"></TextBlock>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="2">
<Button Name="b6" Click="getPrimesCancellation">Get Primes with Cancellation</Button>
<Button Name="cancelButton" Click="cancelGetPrimes" IsEnabled="false">Cancel</Button>
<ProgressBar Name="pb6" HorizontalAlignment="Left" Width="100"></ProgressBar>
<TextBlock Name="tb6"></TextBlock>
</StackPanel>
</Grid>
</Page>
MainPage.xaml の MainPage のクラスに次のコードを追加します。このコードは Primes のオブジェクトとボタンのイベント ハンドラーを定義します。
private PrimesLibrary.Primes primesLib = new PrimesLibrary.Primes();
private async void computePrimes(object sender, RoutedEventArgs e)
{
b1.IsEnabled = false;
tb1.Text = "Working...";
var asyncAction = primesLib.ComputePrimesAsync(0, 100000);
await asyncAction;
tb1.Text = "Done";
b1.IsEnabled = true;
}
private async void computePrimesWithProgress(object sender, RoutedEventArgs e)
{
b2.IsEnabled = false;
tb2.Text = "Working...";
var asyncAction = primesLib.ComputePrimesWithProgressAsync(0, 100000);
asyncAction.Progress = new AsyncActionProgressHandler<double>((action, progress) =>
{
pb1.Value = progress;
});
await asyncAction;
tb2.Text = "Done";
b2.IsEnabled = true;
}
private async void getPrimes(object sender, RoutedEventArgs e)
{
b3.IsEnabled = false;
tb3.Text = "Working...";
var asyncOperation = primesLib.GetPrimesAsync(0, 100000);
await asyncOperation;
tb3.Text = "Found " + asyncOperation.GetResults().Count + " primes";
b3.IsEnabled = true;
}
private async void getPrimesWithProgress(object sender, RoutedEventArgs e)
{
b4.IsEnabled = false;
tb4.Text = "Working...";
var asyncOperation = primesLib.GetPrimesWithProgressAsync(0, 100000);
asyncOperation.Progress = new AsyncOperationProgressHandler<IList<int>, double>((operation, progress) =>
{
pb4.Value = progress;
});
await asyncOperation;
tb4.Text = "Found " + asyncOperation.GetResults().Count + " primes";
b4.IsEnabled = true;
}
private async void getPrimesHandleErrors(object sender, RoutedEventArgs e)
{
b5.IsEnabled = false;
tb5.Text = "Working...";
var asyncOperation = primesLib.GetPrimesWithProgressAsync(-1000, 100000);
asyncOperation.Progress = new AsyncOperationProgressHandler<IList<int>, double>((operation, progress) =>
{
pb5.Value = progress;
});
try
{
await asyncOperation;
tb5.Text = "Found " + asyncOperation.GetResults().Count + " primes";
}
catch (ArgumentException ex)
{
tb5.Text = "ERROR: " + ex.Message;
}
b5.IsEnabled = true;
}
private IAsyncOperationWithProgress<IList<int>, double> asyncCancelableOperation;
private async void getPrimesCancellation(object sender, RoutedEventArgs e)
{
b6.IsEnabled = false;
cancelButton.IsEnabled = true;
tb6.Text = "Working...";
asyncCancelableOperation = primesLib.GetPrimesWithProgressAsync(0, 200000);
asyncCancelableOperation.Progress = new AsyncOperationProgressHandler<IList<int>, double>((operation, progress) =>
{
pb6.Value = progress;
});
try
{
await asyncCancelableOperation;
tb6.Text = "Found " + asyncCancelableOperation.GetResults().Count + " primes";
}
catch (System.Threading.Tasks.TaskCanceledException)
{
tb6.Text = "Operation canceled";
}
b6.IsEnabled = true;
cancelButton.IsEnabled = false;
}
private void cancelGetPrimes(object sender, RoutedEventArgs e)
{
cancelButton.IsEnabled = false;
asyncCancelableOperation.Cancel();
}
これらのメソッドは完全な非同期操作の後で UI を更新するには async と await のキーワードを使用します。、C および Visual Basic で使用できる非同期パターンについては、Windows、C のストア apps の非同期パターンVB Windows のストア apps の非同期パターン" "を参照してください。
getPrimesCancellation と cancelGetPrimes のメソッドは、操作をキャンセルできるようにするように連携します。ユーザーが [キャンセル] のボタンを選択すると、操作をキャンセル cancelGetPrimes のメソッドを呼び出します IAsyncOperationWithProgress<TResult, TProgress>::Cancel。基になる非同期操作を管理する同時実行ランタイムは Windows ランタイム によってキャンセルが完了すると通信するにはキャッチされる内部例外をスローします。キャンセル モデルに関する詳細については、PPL における取り消し処理を参照してください。
重要 |
---|
操作をキャンセルとを同時実行ランタイムが正しく Windows ランタイム に報告できるようにするには、この内部例外の種類をキャッチしないでください。これは、すべての例外 (catch (...)) をキャッチしないことを意味します。すべての例外をキャッチする再スロー Windows ランタイム で取り消し操作を実行できることを確認する例外。 |
次の図は、オプションを選択したら [Primes] アプリケーションを示します。
他の言語で使用できる非同期タスクの作成に create_async を使用する例に Bing の C++ を使用してというオプティマイザーのサンプルをマップしますWindows PPL の C++ 8 の非同期操作ついては、" "を参照してください。
[Top]
スレッド実行の制御
Windows ランタイム は COM スレッド モデルを使用します。このモデルでは、オブジェクトは異なるアパートメント内で同期をどのように扱うかによって、ホストします。スレッド セーフなオブジェクトはマルチスレッド アパートメント (MTA) でホストされます。一つのスレッドがアクセスするオブジェクトは、シングルスレッド アパートメント (STA) でホストされます。
UI があるアプリケーションでは、アプリケーションの ASTA (STA) スレッドは、ウィンドウのメッセージをポンプする必要があり、STA ホストする UI コントロールを更新できるプロセスのスレッドです。これには、2 とおりの結果があります。最初に、アプリケーションを有効にするには、すべての CPU コアおよび I/O 操作は ASTA のスレッドで重要になることを実行しないでください。第 2 に、発生 UI を更新するには ASTA に、バックグラウンド スレッドからマーシャリングする必要があるされます。C ++. Windows ストア アプリケーション MainPage、およびそのほかの XAML では ATSA のすべての実行されます。したがって、ASTA 既定では、宣言に実行されるため、継続の本体のコントロールを直接更新するタスクの継続。ただし、別のタスクのタスクになっている場合、そのすべての継続で MTA 内で入れ子のタスクが実行されます。したがって、どのコンテキストで指定するには、これらのいずれかの継続の実行、明示的に検討する必要があります。
非同期操作から、**IAsyncOperation<TResult>**など、スレッドを無視できるような、特殊な意味を使用して作成されたタスクは詳しく説明します。操作がバックグラウンド スレッド (またはそのスレッドによってまったくサポートされる場合とされない場合があります) 実行されることがありますが、継続は、継続が開始したアパートメントの実行に既定では保証します (つまり、task::thenを呼び出したアパートメントから)。継続の実行コンテキストを制御するために concurrency::task_continuation_context のクラスを使用できます。task_continuation_context のオブジェクトを作成するには、これらの静的なヘルパー メソッドの使用:
継続がバックグラウンド スレッドで実行するように指定するには concurrency::task_continuation_context::use_arbitrary を使用します。
継続が task::thenを呼び出したスレッドで実行されることを指定するには concurrency::task_continuation_context::use_current を使用します。
明示的に継続の実行コンテキストを制御するには task::then のメソッドへの task_continuation_context のオブジェクトを渡すことも、異なるアパートメントにタスクを渡してから、暗黙的に実行コンテキストを制御するには task::then のメソッドを呼び出します。
重要 |
---|
Windows ストア の apps のメイン UI スレッドが STA で実行されるため、STA その STA 既定で実行で作成する継続。したがって、MTA に作成した継続は MTA 内で実行されます。 |
次のセクションでは、ディスクからファイルを読み込むアプリケーションを検索、そのファイルの共通の単語を、次に示します UI で結果を示しています。UI を更新する最後の操作では、UI スレッドで発生します。
重要 |
---|
この動作は Windows ストア の apps に固有です。デスクトップ アプリケーションでは、Where 継続の実行制御しません。代わりに、スケジューラは、各継続を実行するワーカー スレッドを選択します。 |
重要 |
---|
継続の本体の concurrency::task::wait を STA で実行される呼び出さないでください。それ以外の場合、ランタイムはこのメソッドが現在のスレッドをブロックせず、アプリケーションが応答しなくなったようにするために生じることがあるため concurrency::invalid_operation をスローします。ただし、タスク ベースの継続の継続元タスクの結果を受け取るために concurrency::task::get のメソッドを呼び出します。 |
[Top]
例: C++ および XAML Windows ストア App の実行の制御
ディスクから読み込むファイルを C ++.の XAML アプリケーションを検索、そのファイルの共通の単語を、次に示します UI に影響を考慮してください。このアプリケーションを作成し、Windows ストア**[Blue / Z]** プロジェクトを作成し、CommonWordsと参照することによって、Visual Studio で開始します。独自のアプリケーションのマニフェストでは、アプリケーションがドキュメント フォルダーにアクセスできるように [ドキュメント ライブラリ] の機能を指定します。また、アプリケーション マニフェストの申告のセクションにテキスト (.txt) ファイルの種類を追加します。アプリケーションの機能および申告に関する詳細については、アプリケーションのパッケージ化と配置" "を参照してください。
ProgressRing の要素と TextBlock の要素を含めるように MainPage.xaml の Grid の要素を更新します。ProgressRing は、操作が進行中および TextBlock は計算の結果であることを示します。
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ProgressRing x:Name="Progress"/>
<TextBlock x:Name="Results" FontSize="16"/>
</Grid>
pch.h に #include の次のステートメントを追加します。
#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);
MainPage.cpp に using の次のステートメントを追加します。
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 の継続タスクのチェーンを作成します。個々の単語にテキストを分割し、共通の単語を検索最初の 2 種類の継続タスクは時間がかかりますため、バックグラウンドで実行するように明示的に設定されます。したがって、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を呼び出したアパートメントの継続を実行することを再度します。したがって、この例では、UI が含まれていない操作をバックグラウンド スレッドで実行するように指定するには task_continuation_context::use_arbitrary を使用します。
次の図は CommonWords アプリケーションの結果を示しています。
この例では、task がサポートすることに create_async の、暗黙のキャンセル トークンを取得するため、キャンセルをサポートする可能性があります。でタスクが協調的な方法でキャンセルに応答する必要がある場合は cancellation_token のオブジェクトを受け取るように処理関数を定義します。PPL でのキャンセル処理の詳細については、PPL における取り消し処理を参照してください。
[Top]