DispatcherQueue

주요 항목

  • Windows 앱 SDK DispatcherQueue 클래스는 스레드에 대한 작업이 직렬 방식으로 실행되는 우선 순위가 지정된 큐를 관리합니다.
  • 백그라운드 스레드에서 DispatcherQueue의 스레드(예: 특정 스레드에 종속된 개체가 있는 UI 스레드)에서 코드를 실행할 수 있는 수단을 제공합니다.
  • 클래스는 임의 메시지 루프와 정확하게 통합됩니다. 예를 들어 중첩된 메시지 루프의 일반적인 Win32 관용구를 지원합니다.
  • AppWindow 클래스는 DispatcherQueue와 통합됩니다. 지정된 스레드에 대한 DispatcherQueue가 종료되면 AppWindow 인스턴스가 자동으로 제거됩니다.
  • 시간 제한이 만료되면 호출되는 대리자를 등록하는 방법을 제공합니다.
  • 메시지 루프가 종료될 때 구성 요소에 알리고, 선택적으로 미해결 작업이 완료될 때까지 종료를 연기하는 이벤트를 제공합니다. 이렇게 하면 DispatcherQueue를 사용하지만 메시지 루프를 소유하지 않는 구성 요소는 루프가 종료될 때 스레드에서 정리를 수행할 수 있습니다.
  • DispatcherQueue는 스레드 싱글톤입니다(즉, 어떤 주어진 스레드에서든 최대 하나만 실행될 수 있습니다). 기본적으로 스레드에는 DispatcherQueue가 없습니다.
  • 스레드 소유자는 DispatcherQueueController 를 만들어 스레드에 대한 DispatcherQueue 를 초기화할 수 있습니다. 이 시점에서 모든 코드는 스레드의 DispatcherQueue에 액세스할 수 있습니다. 그러나 DispatcherQueueController의 소유자만이 DispatcherQueue를 드레이닝하고 ShutdownStartingShutdownCompleted 이벤트를 발생시키는 DispatcherQueueController.ShutdownQueue 메서드에 액세스할 수 있습니다.
  • 가장 바깥쪽 메시지 루프 소유자는 DispatcherQueue 인스턴스를 만들어야 합니다. 스레드의 가장 바깥쪽 메시지 루프 실행을 담당하는 코드만 디스패치가 완료된 시기를 알 수 있으며, 이는 DispatcherQueue를 종료하기에 적절한 시간입니다. 즉, DispatcherQueue 를 사용하는 구성 요소는 스레드의 메시지 루프를 소유하지 않는 한 DispatcherQueue 를 만들지 않아야 합니다.

런다운

스레드가 이벤트 루프를 종료한 후 DispatcherQueue를 종료해야 합니다. 이렇게 하면 ShutdownStartingShutdownCompleted 이벤트가 발생하고, 추가 인큐잉을 비활성화하기 전에 대기열에 남아 있는 마지막 대기 항목을 모두 처리합니다.

  • DispatcherQueue 소유 메시지 루프를 사용하여 전용 스레드에서 실행되는 DispatcherQueue를 종료하려면 DispatcherQueueController.ShutdownQueueAsync 메서드를 호출합니다.
  • 앱이 임의의 메시지 루프(예: XAML Islands)를 소유하는 시나리오의 경우 동기 DispatcherQueueController.ShutdownQueue 메서드를 호출합니다. 이 메서드는 종료 이벤트를 발생시키고 호출 스레드에서 DispatcherQueue 를 동기적으로 드레이닝합니다.

DispatcherQueueController.ShutdownQueueAsync 또는 DispatcherQueueController.ShutdownQueue를 호출하는 경우 발생하는 이벤트의 순서는 다음과 같습니다.

  • 종료 시작. 앱에서 처리하도록 되어 있습니다.
  • FrameworkShutdownStarting. 프레임워크가 처리하도록 되어 있습니다.
  • FrameworkShutdownCompleted. 프레임워크가 처리하도록 되어 있습니다.
  • 종료 완료. 앱에서 처리하도록 되어 있습니다.

이벤트는 순서대로 종료할 수 있도록 애플리케이션/프레임워크 범주로 구분됩니다. 즉, 프레임워크 종료 이벤트에 앞서 애플리케이션 종료를 명시적으로 발생시켜 애플리케이션이 종료될 때 프레임워크 구성 요소가 사용할 수 없는 상태가 될 위험이 없습니다.

namespace winrt 
{
    using namespace Microsoft::UI::Dispatching;
}

// App runs its own custom message loop.
void RunCustomMessageLoop()
{
    // Create a DispatcherQueue.
    auto dispatcherQueueController{winrt::DispatcherQueueController::CreateOnCurrentThread()};

    // Run a custom message loop. Runs until the message loop owner decides to stop.
    MSG msg;
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!ContentPreTranslateMessage(&msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    // Run down the DispatcherQueue. This single call also runs down the system DispatcherQueue
    // if one was created via EnsureSystemDispatcherQueue:
    // 1. Raises DispatcherQueue.ShutdownStarting event.
    // 2. Drains remaining items in the DispatcherQueue, waits for deferrals.
    // 3. Raises DispatcherQueue.FrameworkShutdownStarting event.
    // 4. Drains remaining items in the DispatcherQueue, waits for deferrals.
    // 5. Disables further enqueuing.
    // 6. Raises the DispatcherQueue.FrameworkShutdownCompleted event.
    // 7. Raises the DispatcherQueue.ShutdownCompleted event.    

    dispatcherQueueController.ShutdownQueue();
}

최외곽 및 재귀적 메시지 루프

DispatcherQueue 는 사용자 지정 메시지 루프를 지원합니다. 그러나 사용자 지정이 필요하지 않은 간단한 앱의 경우 기본 구현을 제공합니다. 이는 개발자의 부담을 없애고 일관되게 올바른 동작을 보장하는 데 도움이 됩니다.

namespace winrt 
{
    using namespace Microsoft::UI::Dispatching;
}

// Simple app; doesn't need a custom message loop.
void RunMessageLoop()
{
    // Create a DispatcherQueue.
    auto dispatcherQueueController{winrt::DispatcherQueueController::CreateOnCurrentThread()};

    // Runs a message loop until a call to DispatcherQueue.EnqueueEventLoopExit or PostQuitMessage.
    dispatcherQueueController.DispatcherQueue().RunEventLoop();

    // Run down the DispatcherQueue. 
    dispatcherQueueController.ShutdownQueue();
}

// May be called while receiving a message.
void RunNestedLoop(winrt::DispatcherQueue dispatcherQueue)
{
    // Runs a message loop until a call to DispatcherQueue.EnqueueEventLoopExit or PostQuitMessage.
    dispatcherQueue.RunEventLoop();
}

// Called to break out of the message loop, returning from the RunEventLoop call lower down the
// stack.
void EndMessageLoop(winrt::DispatcherQueue dispatcherQueue)
{
    // Alternatively, calling Win32's PostQuitMessage has the same effect.
    dispatcherQueue.EnqueueEventLoopExit();
}

시스템 디스패처 관리

일부 Windows 앱 SDK 구성 요소(예: MicaController)는 시스템 구성 요소에 종속되며, 이러한 구성 요소에는 해당 스레드에서 실행 중인 시스템 DispatcherQueue(Windows.System.DispatcherQueue)가 필요합니다.

이러한 경우 시스템 DispatcherQueue 종속성이 있는 구성 요소는 EnsureSystemDispatcherQueue 메서드를 호출하여 앱이 시스템 DispatcherQueue를 관리할 수 없도록 합니다.

이 메서드를 호출하면 Windows 앱 SDK DispatcherQueue는 시스템 DispatcherQueue 수명을 자동으로 관리합니다. 시스템 DispatcherQueue와 함께 Windows 앱 SDK DispatcherQueue 종료합니다. 구성 요소는 메시지 루프가 종료된 후 적절한 정리를 수행하도록 하기 위해 Windows 앱 SDK 시스템 DispatcherQueue 종료 이벤트를 모두 사용합니다.

namespace winrt 
{
    using namespace Microsoft::UI::Composition::SystemBackdrops;
    using namespace Microsoft::UI::Dispatching;
}

// The Windows App SDK component calls this during its startup.
void MicaControllerInitialize(winrt::DispatcherQueue dispatcherQueue)
{
    dispatcherQueue.EnsureSystemDispatcherQueue();

    // If the component needs the system DispatcherQueue explicitly, it can now grab it off the thread.
    winrt::Windows::System::DispatcherQueue systemDispatcherQueue =
        winrt::Windows::System::DispatcherQueue::GetForCurrentThread();
}

void AppInitialize()
{
    // App doesn't need to concern itself with the system DispatcherQueue dependency.
    auto micaController = winrt::MicaController();
}

AppWindow 통합

AppWindow 클래스에는 DispatcherQueue와 통합하는 기능이 있으므로 DispatcherQueueController.ShutdownQueueAsync 또는 DispatcherQueueController.ShutdownQueue 메서드가 호출될 때 AppWindow 개체가 자동으로 제거될 수 있습니다.

호출자가 AppWindow 와 연결된 DispatcherQueue 를 검색할 수 있도록 하는 AppWindow 속성도 있습니다. 컴퍼지션입력 네임스페이스의 다른 개체와 맞춤

AppWindowDispatcherQueue를 인식하기 위해 명시적 옵트인이 필요합니다.

namespace winrt 
{
    using namespace Microsoft::UI::Dispatching;
    using namespace Microsoft::UI::Windowing;
}

void Main()
{
    // Create a Windows App SDK DispatcherQueue.
    auto dispatcherQueueController{winrt::DispatcherQueueController::CreateOnCurrentThread()};

    auto appWindow = AppWindow::Create(nullptr, 0, dispatcherQueueController.DispatcherQueue());

    // Since we associated the DispatcherQueue above with the AppWindow, we're able to retrieve it 
    // as a property. If we were to not associate a dispatcher, this property would be null.
    ASSERT(appWindow.DispatcherQueue() == dispatcherQueueController.DispatcherQueue());

    // Runs a message loop until a call to DispatcherQueue.EnqueueEventLoopExit or PostQuitMessage.
    dispatcherQueueController.DispatcherQueue().RunEventLoop();

    // Rundown the Windows App SDK DispatcherQueue. While this call is in progress, the AppWindow.Destroyed
    // event will be raised since the AppWindow instance is associated with the DispatcherQueue.
    dispatcherQueueController.ShutdownQueue();
}

참고하십시오