Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Ключевые моменты
- Класс DispatcherQueue в Windows App SDK управляет приоритетной очередью, в которой задачи для потока выполняются последовательно.
- Это позволяет фоновым потокам выполнять код в потоке DispatcherQueue (например, в потоке пользовательского интерфейса, к которому привязаны объекты).
- Класс точно интегрируется с произвольными циклами сообщений. Например, он поддерживает распространенный идиом Win32 вложенных циклов сообщений.
- Класс AppWindow интегрируется с DispatcherQueue — когда DispatcherQueue для данного потока завершает работу, экземпляры AppWindow автоматически уничтожаются.
- Позволяет зарегистрировать делегата, который вызывается при истечении времени ожидания.
- Он предоставляет события, которые позволяют компонентам знать, когда цикл сообщений завершается, и при необходимости откладывает завершение работы до завершения невыполненных работ. Это гарантирует, что компоненты, использующие DispatcherQueue, но не управляющие циклом сообщений, могут выполнять очистку в том же потоке при завершении цикла.
- DispatcherQueue — это синглтон для потока (в каждом отдельно взятом потоке может существовать не более одного такого экземпляра). По умолчанию поток не имеет dispatcherQueue.
- Владелец потока может создать DispatcherQueueController для инициализации DispatcherQueue для потока. На этом этапе любой код может получить доступ к объекту DispatcherQueue потока; но доступ к методу DispatcherQueueController.ShutdownQueue, который очищает DispatcherQueue и вызывает события ShutdownStarting и ShutdownCompleted, есть только у владельца DispatcherQueueController.
- Самый внешний владелец цикла сообщений должен создать экземпляр DispatcherQueue . Только код, отвечающий за выполнение внешнего цикла обработки сообщений потока, знает, когда диспетчеризация завершена, и именно тогда следует завершить работу DispatcherQueue. Это означает, что компоненты, которые зависят от DispatcherQueue, не должны создавать DispatcherQueue, если только они не владеют циклом сообщений потока.
Запуск
После выхода потока из цикла обработки событий он должен завершить работу своей DispatcherQueue. При этом вызываются события ShutdownStarting и ShutdownCompleted, а также обрабатываются все оставшиеся ожидающие элементы в очереди перед отключением дальнейшей постановки в очередь.
- Чтобы завершить работу DispatcherQueue, выполняющейся в выделенном потоке с циклом обработки сообщений, принадлежащим DispatcherQueue, вызовите метод DispatcherQueueController.ShutdownQueueAsync.
- В сценариях, когда приложение владеет произвольным циклом сообщений (например, XAML Islands), вызовите синхронный метод DispatcherQueueController.ShutdownQueueQueue. Этот метод вызывает события завершения работы и синхронно обрабатывает все элементы 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 App SDK (например, MicaController) зависят от системных компонентов, которые, в свою очередь, требуют наличия системной DispatcherQueue (Windows.System.DispatcherQueue), выполняющейся в потоке.
В таких случаях компонент, который зависит от системной DispatcherQueue, вызывает метод EnsureSystemDispatcherQueue, избавляя приложение от необходимости управлять системной DispatcherQueue.
При вызове этого метода Windows App SDK DispatcherQueue автоматически управляет жизненным циклом системной DispatcherQueue, завершая работу системной DispatcherQueue одновременно с Windows App SDK DispatcherQueue. Компоненты могут полагаться как на Windows App 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, благодаря чему объекты AppWindow могут автоматически уничтожаться при вызове метода DispatcherQueueController.ShutdownQueueAsync или DispatcherQueueController.ShutdownQueue.
Также у AppWindow есть свойство, которое позволяет вызывающему коду получать связанный с AppWindow объект DispatcherQueue, что согласует его с другими объектами в пространствах имён Composition и Input.
Для работы с DispatcherQueue для AppWindow необходимо явное включение.
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();
}
См. также
- Справочник по API dispatcherQueue
- Миграция функций потоков
- Поддерживайте отзывчивость потока пользовательского интерфейса
- Рекомендации по использованию пула потоков
- Приложение «Галерея WinUI 3» — включает примеры многопоточности и асинхронного программирования
Windows developer