> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XTaskQueueTerminate

> XTaskQueueTerminate

# XTaskQueueTerminate

藉由取消所有擱置中的項目並防止新項目加入佇列，來終止工作佇列。

## 語法

```cpp theme={null}
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 成功或錯誤碼。

## 備註

<Note>在時間敏感執行緒上呼叫此函式並不安全。如需詳細資訊，請參閱[時間敏感執行緒](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/console-dev/overviews/threads/time-sensitive-threads)。</Note>

[XTaskQueueCloseHandle](/zh-TW/reference/system/xtaskqueue/functions/xtaskqueueclosehandle) 只會遞減工作佇列物件上的內部參考計數。如果佇列中仍有回呼，這些回呼會持有佇列物件的參考，而且仍可能被呼叫。這可能會對應用程式關機造成問題。當應用程式關機時，必須確保清除後不會執行任何非預期的回呼。XTaskQueue 提供 **XTaskQueueTerminate** API 來執行佇列的受控終止。

終止工作佇列會執行下列作業：

1. 兩個連接埠的所有回呼都會在 *canceled* 參數設定為 true 的情況下被叫用。
2. 工作連接埠上所有擱置中的回呼都會被分派。將新的回呼提交至工作連接埠將會失敗並傳回 E\_ABORT。
3. 完成連接埠上所有擱置中的回呼都會被分派。將新的回呼提交至完成連接埠將會失敗並傳回 E\_ABORT。

此程序完成之後，如果 wait 為 true，**XTaskQueueTerminate** 就會傳回。如果 wait 為 false，終止會以非同步方式進行。如果您提供終止回呼，它會在終止結束時從完成執行緒叫用。

<Note />

* **XTaskQueueTerminate** 不會關閉佇列控制代碼。終止之後，您仍然需要呼叫 [XTaskQueueCloseHandle](/zh-TW/reference/system/xtaskqueue/functions/xtaskqueueclosehandle)。
* 如果您在透過呼叫 [XTaskQueueDispatch](/zh-TW/reference/system/xtaskqueue/functions/xtaskqueuedispatch) 處理佇列回呼的執行緒上呼叫 **XTaskQueueTerminate**，請勿為 wait 參數傳遞 true，否則您的程式碼可能會發生死結。

下列範例示範如何終止先前建立的工作佇列。

<Note>**SubmitCallback** 是在 [XTaskQueueSubmitCallback](/zh-TW/reference/system/xtaskqueue/functions/xtaskqueuesubmitcallback) 函式的程式碼範例中定義的協助程式函式。</Note>

```cpp theme={null}
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 視窗程序中。它也示範了在將工作佇列與其他執行緒模型整合時，如何正確終止工作佇列。

```cpp theme={null}
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 主機

## 概念文件

* [清除工作佇列](/zh-TW/build/core-features/common/async/async-libraries/async-library-xtaskqueue-example-cleanup-task-queue)
* [時間敏感執行緒](https://learn.microsoft.com/gaming/gdk/docs/gdk-dev/console-dev/overviews/threads/time-sensitive-threads)

## 另請參閱

[XTaskQueue 成員](/zh-TW/reference/system/xtaskqueue/xtaskqueue_members)\
[非同步程式設計模型](/zh-TW/build/core-features/common/async/async-programming-model)\
[非同步工作佇列設計](/zh-TW/build/core-features/common/async/async-task-queue-design)


## Related topics

- [XTaskQueueTerminate](/reference/system/xtaskqueue/functions/xtaskqueueterminate.md)
- [XTaskQueueTerminatedCallback](/reference/system/xtaskqueue/functions/xtaskqueueterminatedcallback.md)
- [Clean up task queue example](/build/core-features/common/async/async-libraries/async-library-xtaskqueue-example-cleanup-task-queue.md)
- [XTaskQueueCloseHandle](/reference/system/xtaskqueue/functions/xtaskqueueclosehandle.md)
- [XTaskQueue](/reference/system/xtaskqueue/xtaskqueue_members.md)
