Использование рабочих очередей
В этом разделе описывается использование рабочих очередей в Microsoft Media Foundation.
- использование рабочих очередей
- Остановка рабочих очередей
- Использование Запланированных Рабочих Элементов
- Использование периодических обратных вызовов
- связанные темы
Использование очередей задач
Рабочая очередь — это эффективный способ выполнения асинхронных операций в другом потоке. Концептуально вы помещаете рабочие элементы в очередь, а очередь содержит поток, который извлекает каждый элемент из очереди и отправляет его. Рабочие элементы реализуются как обратные вызовы с помощью интерфейса IMFAsyncCallback.
Media Foundation создает несколько стандартных очередей, называемых платформенными рабочими очередями. Приложения также могут создавать собственные рабочие очереди, называемые частными рабочими очередями. Список рабочих очередей платформы см. в разделе Идентификаторы рабочих очередей. Чтобы создать частную рабочую очередь, вызовите MFAllocateWorkQueue. Эта функция возвращает идентификатор новой рабочей очереди. Чтобы поместить элемент в очередь, вызовите MFPutWorkItem или MFPutWorkItemEx. В обоих случаях необходимо указать интерфейс обратного вызова.
- MFPutWorkItem принимает указатель на интерфейс IMFAsyncCallback, а также необязательный объект состояния, реализующий IUnknown. Это те же параметры, которые используются в асинхронных методах, как описано в разделе асинхронных методов обратного вызова. Внутри этой функции создается асинхронный объект результата, который передается методу обратного вызова Invoke.
- MFPutWorkItemEx принимает указатель на интерфейс IMFAsyncResult. Этот интерфейс представляет асинхронный объект результата. Создайте этот объект, вызвав MFCreateAsyncResult и указав интерфейс обратного вызова и, при необходимости, объект состояния.
В обоих случаях поток рабочей очереди вызывает метод IMFAsyncCallback::Invoke. Используйте метод Invoke для выполнения рабочего элемента.
Если несколько потоков или компонентов совместно используют одну рабочую очередь, можно вызвать MFLockWorkQueue, чтобы заблокировать рабочую очередь, что предотвращает ее освобождение платформой. Для каждого вызова MFAllocateWorkQueue или MFLockWorkQueueнеобходимо вызвать MFUnlockWorkQueue один раз, чтобы освободить рабочую очередь. Например, если создать рабочую очередь и заблокировать ее один раз, необходимо вызвать MFUnlockWorkQueue дважды, один раз для вызова MFAllocateWorkQueue и один раз для вызова MFLockWorkQueue.
В следующем коде показано, как создать новую рабочую очередь, поместить рабочий элемент в очередь и освободить рабочую очередь.
Дополнительные сведения о рабочих очередях и улучшениях потоков в Windows 8 см. в разделах и.
DWORD idWorkQueue = 0;
HRESULT hr = S_OK;
// Create a new work queue.
hr = MFAllocateWorkQueue(&idWorkQueue);
// Put an item on the queue.
if (SUCCEEDED(hr))
{
hr = MFPutWorkItem(idWorkQueue, pCallback, NULL);
}
// Wait for the callback to be invoked.
if (SUCCEEDED(hr))
{
WaitForSingleObject(hEvent, INFINITE);
}
// Release the work queue.
if (SUCCEEDED(hr))
{
hr = MFUnlockWorkQueue(idWorkQueue);
}
В этом примере предполагается, что pCallback является указателем на интерфейс IMFAsyncCallback приложения. Кроме того, предполагается, что функция обратного вызова задает дескриптор события hEvent. Код ожидает задания этого события перед вызовом MFUnlockWorkQueue.
Потоки рабочей очереди всегда создаются в процессе вызывающего процесса. В каждой рабочей очереди обратные вызовы сериализуются. При вызове MFPutWorkItem дважды с одной рабочей очередью, второй обратный вызов не вызывается до тех пор, пока первый обратный вызов не будет возвращен.
Завершение рабочих очередей
Перед вызовом MFShutdownосвободите все ресурсы, используемые потоками рабочей очереди. Чтобы синхронизировать этот процесс, можно заблокировать платформу Media Foundation, которая запрещает функции MFShutdown закрывать любой поток очереди работы. Если MFShutdown вызывается во время блокировки платформы, MFShutdown ожидает несколько сотен миллисекунда для разблокировки платформы. Если он не разблокирован в течение этого времени, MFShutdown закрывает потоки очереди задач.
Реализация по умолчанию IMFAsyncResult автоматически блокирует платформу Media Foundation при создании объекта результата. Освобождение интерфейса разблокирует платформу. Таким образом, вам почти никогда не придется блокировать платформу напрямую. Но если вы пишете собственную пользовательскую реализацию IMFAsyncResult, то необходимо вручную заблокировать и разблокировать платформу. Чтобы заблокировать платформу, вызовите MFLockPlatform. Чтобы разблокировать платформу, вызовите MFUnlockPlatform. Пример см. в настраиваемых асинхронных объектов результатов.
После вызова MFShutdownнеобходимо убедиться, что платформа разблокирована в течение 5-секундного периода ожидания. Это можно сделать путем освобождения всех IMFAsyncResult указателей, а также путем вызова MFUnlockPlatform, если вы заблокировали платформу вручную. Убедитесь, что освобождаете любые ресурсы, используемые потоками рабочих очередей, иначе может произойти утечка памяти.
Как правило, если приложение завершает работу и освобождает каждый объект Media Foundation перед вызовом MFShutdown, вам не нужно беспокоиться о блокировке. Механизм блокировки просто позволяет потокам рабочих очередей завершаться корректно после вызова MFShutdown.
Использование запланированных рабочих элементов
Обратный вызов можно запланировать после заданного периода времени, вызвав MFScheduleWorkItem или MFScheduleWorkItemEx.
- MFScheduleWorkItem принимает указатель на обратный вызов, необязательный объект состояния и интервал времени ожидания.
- MFScheduleWorkItemEx принимает указатель на асинхронный объект результата и значение времени ожидания.
Укажите время ожидания как отрицательное значение в миллисекундах. Например, чтобы запланировать обратный вызов в течение 5 секунд, используйте значение –5000. Обе функции возвращают значение MFWORKITEM_KEY, которое можно использовать для отмены обратного вызова, передав его в функцию MFCancelWorkItem.
Запланированные рабочие элементы всегда используют очередь рабочих MFASYNC_CALLBACK_QUEUE_TIMER платформы.
Использование периодических обратных вызовов
Функция MFAddPeriodicCallback планирует периодически вызывать обратный вызов, пока не отменяете его. Фиксированный интервал обратного вызова; приложения не могут изменить его. Чтобы узнать точный интервал, вызовите MFGetTimerPeriodicity. Интервал порядка 10 миллисекунд, поэтому эта функция предназначена для ситуаций, когда требуется частый "тик", например, для реализации часов презентации. Если вы хотите запланировать операцию реже, используйте запланированный рабочий элемент, как описано ранее.
В отличие от других обратных вызовов, описанных в этом разделе, периодический обратный вызов не использует интерфейс IMFAsyncCallback. Вместо этого он использует указатель функции. Дополнительные сведения см. в MFPERIODICCALLBACK Callback.
Чтобы отменить периодический обратный вызов, вызовите MFRemovePeriodicCallback.
Периодические обратные вызовы используют рабочую очередь MFASYNC_CALLBACK_QUEUE_TIMER платформы.
Связанные разделы