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와 함께 실패합니다.
이 프로세스가 완료된 후 대기가 true이면 XTaskQueueTerminate가 반환됩니다. 대기가 false이면 종료가 비동기적으로 발생합니다. 종료 콜백을 제공하는 경우, 종료가 끝날 때 완료 스레드에서 호출됩니다.
참고 항목
- XTaskQueueTerminate는 큐 핸들을 닫지 않습니다. 종료 후에도 여전히 XTaskQueueCloseHandle을 호출해야 합니다.
- XTaskQueueDispatch를 호출하여 큐 콜백을 서비스하는 스레드에서 XTaskQueueTerminate를 호출할 경우, 대기 매개 변수에 대해 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 콘솔