Понимание очереди диспетчера

Мне кажется, мне нужна помощь в понимании Dispatcher Queue.

Когда приходит новая работа, она добавляется в начале очереди диспетчера и когда диспетчер хочет обработать рабочий элемент, он будет удален с самого начала.

В более общих терминах: если есть работа, она хранится в форме FIFO внутри очереди и обрабатывается так долго, пока не осталось работы.

Документация MSDN здесь относится к loop и frame:

The Dispatcher processes the work item queue in a loop. The loop is referred to as a frame.

Но где цикл в этом контексте? Для меня цикл - это нечто, что итерирует что-то, и когда оно достигает цели, оно начинается снова.

А какое понятие a frame? Согласно документации MSDN, кадр представляет собой набор рабочих элементов внутри очереди? Если это так, как должен использоваться статический метод Disptatcher.PushFrame()?

И самый интересный вопрос: есть ли способ получить текущее состояние очереди, особенно количество элементов в очереди.

Выполняется ли это, если запускается метод, который был вызван раньше (и поэтому помещен в очередь диспетчера), который затем удаляется из очереди или длится внутри в течение еще одного периода времени?

Я знаю, столько вопросов: -)

Ответ 1

В документации Dispatcher очень мало документации, поэтому вам придется немного разбираться, чтобы узнать о внутренней работе.

Диспетчер - это в основном то, что выполняет работу над приложением Message Pump. Этот вопрос находится поверх цикла сообщений Windows.

Как следствие, может быть только одно приложение Dispatcher - глобальный объект диспетчера, доступный через Application.Current.Dispatcher. Другие диспетчеры могут получить доступ к Dispatcher.CurrentDispatcher, который согласно документации

Получает диспетчер для текущего потока и создает новый диспетчер, если он еще не связан с потоком.

Однако вызов Run в этом новом диспетчере будет заблокирован.

Когда вы выполняете Dispatcher.PushFrame, он в основном подталкивает кадр к текущему диспетчеру. Все, что наследуется от DispatcherObject, например DispatcherFrame, будет иметь свой диспетчер, установленный в текущий. Мы можем проверить это, посмотрев на его конструктор.

private Dispatcher _dispatcher;

protected DispatcherObject()
{
    this._dispatcher = Dispatcher.CurrentDispatcher;
}

Конечно, простого цикла событий недостаточно - иногда вам нужно подорвать текущий цикл событий, чтобы заставить другую работу работать. И поэтому у вас есть DispatcherFrame. Это то, что на самом деле составляет цикл событий. Когда вы вставляете кадр в диспетчер, это происходит:

while (frame.Continue)
        {
            if (!this.GetMessage(ref msg, IntPtr.Zero, 0, 0))
            {
                break;
            }
            this.TranslateAndDispatchMessage(ref msg);
        }

В TranslateAndDispatchMessage указано, что приоритетная очередь в диспетчере получает оценку после того, как сообщение выведено.

Если для диспетчера требуется много времени, он временно останавливает цикл событий и, поскольку он не отвечает на сигнализацию, приложение похоже на то, что перестает отвечать на запросы.

Здесь статья, в которой используется кадр, чтобы заставить пользовательский интерфейс отвечать, позволяя коротко запустить цикл событий.

Как для доступа к очереди, так и есть, нет способа узнать состояние очереди вне Диспетчера. Это внутренняя деталь, и это разумно, что она не подвергается.