DispatcherQueue
중요 사항
- Windows 앱 SDK DispatcherQueue 클래스는 스레드에 대한 작업이 직렬 방식으로 실행되는 우선 순위가 지정된 큐를 관리합니다.
- 백그라운드 스레드가 DispatcherQueue의 스레드에서 코드를 실행하는 방법을 제공합니다(예: 스레드 선호도가 있는 개체가 라이브인 UI 스레드).
- 클래스는 임의 메시지 루프와 정확하게 통합됩니다. 예를 들어 중첩된 메시지 루프의 일반적인 Win32 관용구를 지원합니다.
- AppWindow 클래스는 DispatcherQueue와 통합됩니다. 지정된 스레드에 대한 DispatcherQueue가 종료되면 AppWindow 인스턴스가 자동으로 제거됩니다.
- 시간 제한이 만료되면 호출되는 대리자를 등록하는 방법을 제공합니다.
- 메시지 루프가 종료될 때 구성 요소에 알리고, 선택적으로 미해결 작업이 완료될 때까지 종료를 연기하는 이벤트를 제공합니다. 이렇게 하면 DispatcherQueue를 사용하지만 메시지 루프를 소유하지 않는 구성 요소가 루프가 종료될 때 스레드에서 정리를 수행할 수 있습니다.
- DispatcherQueue는 스레드 싱글톤입니다(지정된 스레드에서 실행되는 스레드는 대부분 있을 수 있습니다). 기본적으로 스레드에는 DispatcherQueue가 없습니다.
- 스레드 소유자는 DispatcherQueueController를 만들어 스레드에 대한 DispatcherQueue를 초기화할 수 있습니다. 이 시점에서 모든 코드는 스레드의 DispatcherQueue에 액세스할 수 있지만 DispatcherQueueController의 소유자만 DispatcherQueue를 드레이닝하고 ShutdownStarted 및 ShutdownCompleted 이벤트를 발생시키는 DispatcherQueueController.ShutdownQueue 메서드에 액세스할 수 있습니다.
- 최외각 메시지 루프 소유자는 DispatcherQueue 인스턴스를 만들어야 합니다. 스레드의 최외각 메시지 루프 실행을 담당하는 코드만 디스패치가 완료된 시기를 알 수 있으며, 이는 DispatcherQueue를 종료하기에 적절한 시간입니다. 즉, DispatcherQueue를 사용하는 구성 요소는 스레드의 메시지 루프를 소유하지 않는 한 DispatcherQueue를 만들지 않아야 합니다.
런다운
스레드가 이벤트 루프를 종료한 후 DispatcherQueue를 종료해야 합니다. 이렇게 하면 ShutdownStarting 및 ShutdownCompleted 이벤트가 발생하며, 큐에 추가 큐를 사용하지 않도록 설정하기 전에 큐에 대기 중인 최종 항목을 드레이닝합니다.
- DispatcherQueue 소유 메시지 루프를 사용하여 전용 스레드에서 실행되는 DispatcherQueue를 종료하려면 DispatcherQueueController.ShutdownQueueAsync 메서드를 호출합니다.
- 앱이 임의의 메시지 루프(예: XAML Islands)를 소유하는 시나리오의 경우 동기 DispatcherQueueController.ShutdownQueue 메서드를 호출합니다. 이 메서드는 종료 이벤트를 발생시키고 호출 스레드에서 DispatcherQueue 를 동기적으로 드레이닝합니다.
DispatcherQueueController.ShutdownQueueAsync 또는 DispatcherQueueController.ShutdownQueue를 호출하는 경우 발생하는 이벤트의 순서는 다음과 같습니다.
- ShutdownStarting. 처리할 앱용입니다.
- FrameworkShutdownStarting. 처리할 프레임워크용입니다.
- FrameworkShutdownCompleted. 처리할 프레임워크용입니다.
- ShutdownCompleted. 처리할 앱용입니다.
순서대로 종료할 수 있도록 이벤트는 애플리케이션/프레임워크 범주로 구분됩니다. 즉, 프레임워크 종료 이벤트에 앞서 애플리케이션 종료를 명시적으로 발생시켜 애플리케이션이 종료될 때 프레임워크 구성 요소가 사용할 수 없는 상태가 될 위험이 없습니다.
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))
{
TranslateMesasge(&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의 수명을 자동으로 관리하여 Windows 앱 SDK DispatcherQueue와 함께 시스템 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 속성도 있습니다.
AppWindow는 DispatcherQueue를 인식하기 위한 명시적 설정이 필요합니다.
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()};
var appWindow = AppWindow.Create(nullptr, 0, dispatcherQueueController.DispatcherQueue());
// Since we associated the DispatcherQueue above with the AppWindow, we're able to retreive 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.Destoyed
// event will be raised since the AppWindow instance is associated with the DispatcherQueue.
dispatcherQueueController.ShutdownQueue();
}
Windows developer