주요 항목
- Windows 앱 SDK DispatcherQueue 클래스는 스레드에 대한 작업이 직렬 방식으로 실행되는 우선 순위가 지정된 큐를 관리합니다.
- 백그라운드 스레드에서 DispatcherQueue의 스레드(예: 특정 스레드에 종속된 개체가 있는 UI 스레드)에서 코드를 실행할 수 있는 수단을 제공합니다.
- 클래스는 임의 메시지 루프와 정확하게 통합됩니다. 예를 들어 중첩된 메시지 루프의 일반적인 Win32 관용구를 지원합니다.
- AppWindow 클래스는 DispatcherQueue와 통합됩니다. 지정된 스레드에 대한 DispatcherQueue가 종료되면 AppWindow 인스턴스가 자동으로 제거됩니다.
- 시간 제한이 만료되면 호출되는 대리자를 등록하는 방법을 제공합니다.
- 메시지 루프가 종료될 때 구성 요소에 알리고, 선택적으로 미해결 작업이 완료될 때까지 종료를 연기하는 이벤트를 제공합니다. 이렇게 하면 DispatcherQueue를 사용하지만 메시지 루프를 소유하지 않는 구성 요소는 루프가 종료될 때 스레드에서 정리를 수행할 수 있습니다.
- DispatcherQueue는 스레드 싱글톤입니다(즉, 어떤 주어진 스레드에서든 최대 하나만 실행될 수 있습니다). 기본적으로 스레드에는 DispatcherQueue가 없습니다.
- 스레드 소유자는 DispatcherQueueController 를 만들어 스레드에 대한 DispatcherQueue 를 초기화할 수 있습니다. 이 시점에서 모든 코드는 스레드의 DispatcherQueue에 액세스할 수 있습니다. 그러나 DispatcherQueueController의 소유자만이 DispatcherQueue를 드레이닝하고 ShutdownStarting 및 ShutdownCompleted 이벤트를 발생시키는 DispatcherQueueController.ShutdownQueue 메서드에 액세스할 수 있습니다.
- 가장 바깥쪽 메시지 루프 소유자는 DispatcherQueue 인스턴스를 만들어야 합니다. 스레드의 가장 바깥쪽 메시지 루프 실행을 담당하는 코드만 디스패치가 완료된 시기를 알 수 있으며, 이는 DispatcherQueue를 종료하기에 적절한 시간입니다. 즉, DispatcherQueue 를 사용하는 구성 요소는 스레드의 메시지 루프를 소유하지 않는 한 DispatcherQueue 를 만들지 않아야 합니다.
런다운
스레드가 이벤트 루프를 종료한 후 DispatcherQueue를 종료해야 합니다. 이렇게 하면 ShutdownStarting 및 ShutdownCompleted 이벤트가 발생하고, 추가 인큐잉을 비활성화하기 전에 대기열에 남아 있는 마지막 대기 항목을 모두 처리합니다.
- 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 속성도 있습니다. 컴퍼지션 및 입력 네임스페이스의 다른 개체와 맞춤
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()};
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();
}
참고하십시오
- DispatcherQueue API 참조
- 스레딩 기능 마이그레이션
- UI 스레드 응답 유지
- 스레드 풀 사용에 대한 모범 사례
- WinUI 3 갤러리 앱 - 스레딩 및 비동기 샘플 포함
Windows developer