XTaskQueueTerminate
保留中のすべての項目を取り消し、新しい項目がキューに入らないようにして、タスク キューを終了します。
構文
HRESULT XTaskQueueTerminate(
XTaskQueueHandle queue,
bool wait,
void* callbackContext,
XTaskQueueTerminatedCallback* callback
)
パラメーター
queue _In_
型: XTaskQueueHandle
終了するキュー。
wait _In_
型: bool
終了が完了するまで待機する場合は true。
callbackContext _In_opt_
型: void*
コールバックに渡されるオプションのコンテキスト ポインター。
callback _In_opt_
型: XTaskQueueTerminatedCallback*
キューが終了したときに呼び出されるオプションのコールバック。
戻り値
型: HRESULT
HRESULT 成功またはエラー コード。
解説
注意
この関数は、時間依存のスレッドで呼び出すのに安全ではありません。 詳細については、「時間依存のスレッド」を参照してください。
XTaskQueueCloseHandle では、タスク キュー オブジェクトの内部参照カウントのデクリメントのみが行われます。 キューにコールバックがまだある場合、それらのコールバックはキュー オブジェクトへの参照を保持しており、呼び出される可能性があります。 このためアプリのシャットダウンに関する問題が発生することがあります。 アプリがシャットダウンするとき、クリーンアップ後に間違ったコールバックが実行されないことを確認する必要があります。 XTaskQueue によって、キューの終了を制御して実行するために XTaskQueueTerminate API が提供されます。
タスク キューの終了では次の操作が実行されます。
- 両方のポートのすべてのコールバックが、canceled パラメーターが true に設定されて呼び出されます。
- 作業ポートで保留中のすべてのコールバックがディスパッチされます。 作業ポートへの新しいコールバックの送信は、E_ABORT で失敗します。
- 完了ポートで保留中のすべてのコールバックがディスパッチされます。 完了ポートへの新しいコールバックの送信は、E_ABORT で失敗します。
このプロセスが完了した後、wait が true の場合に XTaskQueueTerminate が戻ります。 wait が false の場合、終了は非同期で行われます。 終了コールバックを指定すると、それは終了の最後に完了スレッドから呼び出されます。
注意
- XTaskQueueTerminate はキュー ハンドルを閉じません。 終了した後で、XTaskQueueCloseHandle を呼び出す必要があります。
- XTaskQueueDispatch を呼び出すことでキューのコールバックを処理しているスレッドで XTaskQueueTerminate を呼び出す場合は、wait パラメーターに true を渡さないでください。そうすると、コードでデッドロックが発生する可能性があります。
次の例は、以前に作成されたタスク キューを終了する方法を示します。
注意
SubmitCallback は、 XTaskQueueSubmitCallback 関数のコード例で定義されているヘルパー関数です。
void CreatingTaskQueue()
{
XTaskQueueHandle queue;
HRESULT hr = XTaskQueueCreate(XTaskQueueDispatchMode::ThreadPool, XTaskQueueDispatchMode::ThreadPool, &queue);
if (FAILED(hr))
{
printf("Creating queue failed: 0x%x\r\n", hr);
return;
}
SubmitCallbacks(queue);
// Wait a while for the callbacks to run
Sleep(1000);
XTaskQueueTerminate(queue, true, nullptr, nullptr);
}
タスク キューは UI スレッドに統合できます。 通常は、コールバックが UI スレッド上で実行するためには、完了ポートのキューに入れる必要があります。 この例では、処理のためにスレッド プールを使用しますが、完了ポート コールバックを Win32 ウィンドウ プロシージャに統合します。 また、別のスレッド モデルに統合する際に、タスク キューを適切に終了する方法も示します。
struct WorkData
{
HWND hwnd;
WCHAR text[80];
};
void CALLBACK WorkCompletion(void* context, bool cancel)
{
WorkData* data = (WorkData*)context;
if (!cancel)
{
SetWindowText(data->hwnd, data->text);
}
delete data;
}
void CALLBACK BackgroundWork(void* context, bool cancel)
{
if (!cancel)
{
WorkData* data = new WorkData;
data->hwnd = (HWND)context;
if (GetTimeFormatEx(
LOCALE_NAME_USER_DEFAULT, 0, nullptr,
nullptr, data->text, 80) == 0)
{
swprintf_s(data->text, L"Error : %d", GetLastError());
}
// Now take our formatted string and submit it as a completion callback
XTaskQueueSubmitCallback(
g_queue,
XTaskQueuePort::Completion,
data,
WorkCompletion);
}
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HRESULT hr;
switch (msg)
{
case WM_CREATE:
// We will do work on the thread pool, but completion
// callbacks should be manual so we can integrate them with
// the message loop.
hr = XTaskQueueCreate(
XTaskQueueDispatchMode::ThreadPool,
XTaskQueueDispatchMode::Manual,
&g_queue);
if (SUCCEEDED(hr))
{
hr = XTaskQueueRegisterMonitor(g_queue, hwnd,
[](void* context, XTaskQueueHandle, XTaskQueuePort port)
{
// If a new callback was submitted to the completion port, post a message
// so we dispatch it in our message loop
if (port == XTaskQueuePort::Completion)
{
HWND hwnd = static_cast<HWND>(context);
PostMessage(hwnd, WM_QUEUE_COMPLETION, 0, 0);
}
}, &g_monitorToken);
}
if (FAILED(hr))
{
PostQuitMessage(1);
return 0;
}
break;
case WM_LBUTTONDOWN:
hr = XTaskQueueSubmitCallback(
g_queue,
XTaskQueuePort::Completion,
hwnd,
BackgroundWork);
if (FAILED(hr))
{
MessageBox(hwnd, L"Failed to submit callback.", L"Error", MB_OK);
}
break;
case WM_QUEUE_COMPLETION:
XTaskQueueDispatch(g_queue, XTaskQueuePort::Completion, 0);
break;
case WM_CLOSE:
// Terminate the task queue. When done, destroy our window. The termination callback
// is queued to the completion port, so it will already be on the UI thread.
hr = XTaskQueueTerminate(g_queue, false, hwnd, [](void* context)
{
HWND hwnd = static_cast<HWND>(context);
DestroyWindow(hwnd);
XTaskQueueUnregisterMonitor(g_queue, g_monitorToken);
XTaskQueueCloseHandle(g_queue);
});
if (SUCCEEDED(hr))
{
// Prevent DefWndProc from destroying our window because
// the termination callback will do it.
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void TestWndProc()
{
WNDCLASS wndClass;
ZeroMemory(&wndClass, sizeof(wndClass));
wndClass.lpfnWndProc = WndProc;
wndClass.lpszClassName = L"TestClass";
wndClass.hInstance = GetModuleHandle(nullptr);
wndClass.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
ATOM c = RegisterClass(&wndClass);
HWND h = CreateWindow(L"TestClass", L"Window",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
10, 10, 300, 100, nullptr, nullptr,
GetModuleHandle(nullptr), 0);
if (!h)
{
return;
}
MSG m;
while (GetMessage(&m, nullptr, 0, 0))
{
TranslateMessage(&m);
DispatchMessage(&m);
}
}
要件
ヘッダー: XTaskQueue.h
ライブラリ: xgameruntime.lib
サポートされているプラットフォーム: Windows、Xbox One ファミリー本体、Xbox Series 本体