カスタム プロバイダーのセット アップ例
このトピックでは、カスタム非同期プロバイダーをセット アップする方法の例を紹介します。 カスタム非同期プロバイダーを書き込むには、非同期方式の場合、XAsyncBegin を呼び出して開始します。 この関数は、例えば、ステージの変更、コールバックのエンキュー、完了のトリガなどの処理を実装するコールバック パラメーターがあります。
struct Context
{
uint64_t result;
};
Context* context = new Context{ 0 };
// Assume that the async block is already filled out with the completion callback and task queue.
HRESULT hr = XAsyncBegin(async, context, ProviderFuncIdentity, __FUNCTION__,
[](XAsyncOp op, const XAsyncProviderData* providerData)
{
Context* context =
reinterpret_cast<Context*>(providerData->context);
switch (op)
{
case XAsyncOp::Begin:
return XAsyncSchedule(providerData->async, 0);
case XAsyncOp::Cleanup:
delete context;
break;
case XAsyncOp::GetResult:
memcpy(providerData->buffer, &context->result, sizeof(uint64_t));
break;
case XAsyncOp::DoWork:
context->result = 12345678;
XAsyncComplete(providerData->async, S_OK, sizeof(uint64_t));
break;
case XAsyncOp::Cancel:
// This call can't be canceled.
break;
}
return S_OK;
});
ここには展開するものが多数ありますが、基本概念は簡単です。XAsyncBegin
を呼び出し、これにプロバイダーのコールバックを指定して異なる状態変更を処理することです。 非同期ブロックには、使用するタスク キューおよび完了コールバックのオプション実装が含まれています。 次に、コールバックは、以下の表に示すように、非同期タスクのランタイム用に 5 種類のケース を処理する必要があります。
プロバイダー ケース | 責任 |
---|---|
Begin |
XAsyncBegin への呼び出しによって、すぐに呼び出されます。 この場合、非同期作業のコールバックをタスク キューにスケジュールする必要があります。 これは XAsyncSchedule の呼び出しによって処理されます。 このコールバックをエンキューし、タスク キューの作業ポートを介して DoWork ケースを使用して再実行します。 |
Cleanup |
非同期タスクが終了したときに呼び出され、追跡用に作成された内部データが削除できます。 前述のサンプル コードでは、このケースは、結果データを追跡し続けるために割り当てられた Context 構造体をクリーンアップします。 |
GetResult |
ユーザーが XAsyncGetResult を呼び出すと呼び出されます。 このケースは、ケースに渡された出力バッファーに書き込む必要があります。 したがって、元の非同期結果は、どこかに保存されている必要があります。 上記のサンプルコードは、これを Context 構造体に保存します。非同期タスクからデータを返す非同期 Microsoft Game Development Kit (GDK) API 関数は、 XAsyncGetResult を内部的に呼び出し、そのデータを呼び出し元に適した形式に変換します。 結果を処理するには、この方法を推奨します。 |
DoWork |
作業ポートをディスパッチするタスク キューを介して呼び出されます。 つまり、このコールバックのスタック フレームが、タスク キューのセットアップ方法に基づいて目的のスレッドで実行されていることを意味します。 いかなる作業も、ここで実行する必要があります。 XAsyncRun の内部の非同期プロバイダー実装では、これは、渡された作業コールバックを実行する場所です。 カスタム プロバイダーの場合は、作業はコールバックで直接実行するか、カスタム方式を使用して機能をカプセル化できます。 作業が完了したら、XAsyncComplete を呼び出す必要があります。 この関数は 2 つのタスクを実行します。 まず、データ サイズを指定することによって出力データが必要かどうかを指定します。 ゼロより大きい値が指定された場合、 GetResult ケースの書き込み先に内部バッファーが割り当てられます。 次に、実行する完了コールバックの呼び出しをタスク キューの完了ポートにエンキューします。
XAsyncComplete に渡される完了ステータス コードは XAsyncGetStatus の呼び出しによって返されるコードになります。 |
Cancel |
XAsyncCancel への外部呼び出しによってトリガーされます。 このケースが実装されていない場合、結果として何も起こりません。 キャンセルを許可するには、プロバイダーは、実行中のすべての作業の停止命令を送信できる必要があります。
DoWork ケースは、E_ABORT のステータスで XAsyncComplete を呼び出す必要があります。 |