DispatcherQueue

Sorotan

  • Kelas DispatcherQueue di SDK Aplikasi Windows mengelola antrean berprioritas tempat tugas-tugas untuk suatu utas dijalankan secara berurutan.
  • Ini menyediakan cara bagi utas latar belakang untuk menjalankan kode pada utas milik DispatcherQueue (misalnya, utas UI tempat objek yang memiliki afinitas terhadap utas berada).
  • Kelas ini terintegrasi secara tepat dengan loop pesan sebarang. Misalnya, ini mendukung idiom Win32 umum dari perulangan pesan berlapis.
  • Kelas AppWindow terintegrasi dengan DispatcherQueue—saat DispatcherQueue untuk utas tertentu dimatikan, instans AppWindow secara otomatis dihancurkan.
  • Ini menyediakan sarana untuk mendaftarkan delegasi yang dipanggil ketika batas waktu berakhir.
  • Ini menyediakan event yang memberi tahu komponen saat loop pesan akan berakhir, dan secara opsional menunda penghentian tersebut hingga pekerjaan yang masih tertunda selesai. Hal itu memastikan komponen yang menggunakan DispatcherQueue, tetapi tidak mengelola sendiri loop pesan, dapat melakukan pembersihan di utas yang sama saat loop berakhir.
  • DispatcherQueue adalah singleton utas (artinya, paling banyak hanya ada satu instance yang berjalan pada setiap utas tertentu). Secara default, utas tidak memiliki DispatcherQueue.
  • Pemilik utas dapat membuat DispatcherQueueController untuk menginisialisasi DispatcherQueue untuk utas tersebut. Pada saat itu, kode apa pun dapat mengakses DispatcherQueue milik utas tersebut; tetapi hanya pemilik DispatcherQueueController yang dapat mengakses metode DispatcherQueueController.ShutdownQueue, yang mengosongkan DispatcherQueue serta memicu event ShutdownStarting dan ShutdownCompleted.
  • Pemilik loop pesan terluar harus membuat instans DispatcherQueue. Hanya kode yang bertanggung jawab untuk menjalankan perulangan pesan terluar suatu utas yang mengetahui kapan dispatch selesai, dan itulah waktu yang tepat untuk mematikan DispatcherQueue. Artinya, komponen yang bergantung pada DispatcherQueue tidak boleh membuat DispatcherQueue kecuali komponen tersebut mengelola loop pesan utas tersebut.

Ringkasan

Setelah utas mengakhiri loop peristiwanya, utas tersebut harus menonaktifkan DispatcherQueue-nya. Tindakan ini memicu peristiwa ShutdownStarting dan ShutdownCompleted, serta mengosongkan item terakhir yang masih tertunda dalam antrean sebelum menonaktifkan penambahan item ke antrean selanjutnya.

  • Untuk mematikan DispatcherQueue yang berjalan pada utas khusus dengan perulangan pesan milik DispatcherQueue, panggil metode DispatcherQueueController.ShutdownQueueAsync .
  • Untuk skenario ketika aplikasi memiliki message loop arbitrer (misalnya, XAML Islands), panggil metode sinkron DispatcherQueueController.ShutdownQueue. Metode tersebut memicu event penghentian, dan mengosongkan DispatcherQueue secara sinkron pada utas pemanggil.

Saat Anda memanggil DispatcherQueueController.ShutdownQueueAsync atau DispatcherQueueController.ShutdownQueue, urutan peristiwa yang diangkat adalah sebagai berikut:

  • ShutdownStarting. Ditujukan agar dapat ditangani oleh aplikasi.
  • FrameworkShutdownStarting. Ditujukan untuk kerangka kerja yang akan ditangani.
  • FrameworkShutdownCompleted. Ditujukan untuk kerangka kerja yang akan ditangani.
  • Pematian selesai. Ditujukan agar dapat ditangani oleh aplikasi.

Kejadian dipisahkan ke dalam kategori aplikasi/kerangka kerja agar proses penghentian secara tertib dapat dilakukan. Artinya, dengan secara eksplisit memicu penghentian aplikasi sebelum peristiwa penghentian framework, tidak ada risiko bahwa komponen framework akan berada dalam keadaan tidak dapat digunakan saat aplikasi sedang dihentikan.

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();
}

Perulangan pesan terluar dan rekursif

DispatcherQueue mendukung perulangan pesan kustom. Namun, untuk aplikasi sederhana yang tidak memerlukan kustomisasi, kami menyediakan implementasi default. Itu menghapus beban dari pengembang, dan membantu memastikan perilaku yang benar secara konsisten.

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();
}

Manajemen dispatcher sistem

Beberapa komponen SDK Aplikasi Windows (misalnya, MicaController) bergantung pada komponen sistem yang pada gilirannya memerlukan sistem DispatcherQueue (Windows. System.DispatcherQueue) berjalan pada utas.

Dalam kasus tersebut, komponen yang memiliki dependensi DispatcherQueue sistem memanggil metode EnsureSystemDispatcherQueue , membebaskan aplikasi Anda dari mengelola sistem DispatcherQueue.

Dengan metode yang disebut, SDK Aplikasi Windows DispatcherQueue mengelola masa pakai sistem DispatcherQueue secara otomatis, mematikan sistem DispatcherQueue bersama SDK Aplikasi Windows DispatcherQueue. Komponen mungkin mengandalkan peristiwa penghentian SDK Aplikasi Windows maupun sistem DispatcherQueue untuk memastikan bahwa pembersihan dilakukan dengan tepat setelah loop pesan berakhir.

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();
}

Integrasi AppWindow

Kelas AppWindow memiliki fungsionalitas yang mengintegrasikannya dengan DispatcherQueue, sehingga objek AppWindow dapat secara otomatis dihancurkan ketika metode DispatcherQueueController.ShutdownQueueAsync atau DispatcherQueueController.ShutdownQueue dipanggil.

Ada juga properti AppWindow yang memungkinkan penelepon untuk mengambil DispatcherQueue yang terkait dengan AppWindow; menyelaraskannya dengan objek lain dalam namespace Komposisi dan Input .

AppWindow memerlukan keikutsertaan eksplisit Anda untuk mengetahui 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();
}

Baca juga