Usando filas de trabalho

Este tópico descreve como usar filas de trabalho no Microsoft Media Foundation.

Usando filas de trabalho

Uma fila de trabalho é uma maneira eficiente de executar operações assíncronas em outro thread. Conceitualmente, você coloca itens de trabalho na fila e a fila tem um thread que efetua pull de cada item da fila e o despacha. Os itens de trabalho são implementados como retornos de chamada usando a interface IMFAsyncCallback .

O Media Foundation cria várias filas de trabalho padrão, chamadas filas de trabalho de plataforma. Os aplicativos também podem criar suas próprias filas de trabalho, chamadas de filas de trabalho privadas. Para obter uma lista das filas de trabalho da plataforma, consulte Identificadores de fila de trabalho. Para criar uma fila de trabalho privada, chame MFAllocateWorkQueue. Essa função retorna um identificador para a nova fila de trabalho. Para colocar um item na fila, chame MFPutWorkItem ou MFPutWorkItemEx. Em ambos os casos, você deve especificar uma interface de retorno de chamada.

  • MFPutWorkItem usa um ponteiro para a interface IMFAsyncCallback , além de um objeto de estado opcional que implementa IUnknown. Esses são os mesmos parâmetros usados em métodos assíncronos, conforme descrito no tópico Métodos de Retorno de Chamada Assíncronos. Internamente, essa função cria um objeto de resultado assíncrono, que é passado para o método Invoke do retorno de chamada.
  • MFPutWorkItemEx usa um ponteiro para a interface IMFAsyncResult . Essa interface representa um objeto de resultado assíncrono. Crie esse objeto chamando MFCreateAsyncResult e especificando sua interface de retorno de chamada e, opcionalmente, um objeto de estado.

Em ambos os casos, o thread da fila de trabalho chama o método IMFAsyncCallback::Invoke . Use o método Invoke para executar o item de trabalho.

Se mais de um thread ou componente compartilhar a mesma fila de trabalho, você poderá chamar MFLockWorkQueue para bloquear a fila de trabalho, o que impede que a plataforma a libere. Para cada chamada para MFAllocateWorkQueue ou MFLockWorkQueue, você deve chamar MFUnlockWorkQueue uma vez para liberar a fila de trabalho. Por exemplo, se você criar uma nova fila de trabalho e bloqueá-la uma vez, deverá chamar MFUnlockWorkQueue duas vezes, uma vez para a chamada para MFAllocateWorkQueue e uma vez para a chamada para MFLockWorkQueue.

O código a seguir mostra como criar uma nova fila de trabalho, colocar um item de trabalho na fila e liberar a fila de trabalho.

Consulte Melhorias de fila de trabalho e threading para obter informações adicionais sobre filas de trabalho em 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);
}

Este exemplo pressupõe que pCallback é um ponteiro para a interface IMFAsyncCallback do aplicativo. Ele também pressupõe que o retorno de chamada define o identificador de evento hEvent . O código aguarda que esse evento seja definido antes de chamar MFUnlockWorkQueue.

Os threads da fila de trabalho são sempre criados no processo do chamador. Em cada fila de trabalho, os retornos de chamada são serializados. Se você chamar MFPutWorkItem duas vezes com a mesma fila de trabalho, o segundo retorno de chamada não será invocado até que o primeiro retorno de chamada seja retornado.

Desligando filas de trabalho

Antes de chamar MFShutdown, libere todos os recursos que estão sendo usados por threads de fila de trabalho. Para sincronizar esse processo, você pode bloquear a plataforma Media Foundation, o que impede que a função MFShutdown feche threads de fila de trabalho. Se MFShutdown for chamado enquanto a plataforma estiver bloqueada, o MFShutdown aguardará algumas centenas de milissegundos para que a plataforma seja desbloqueada. Se ele não for desbloqueado dentro desse tempo, o MFShutdown fechará os threads da fila de trabalho.

A implementação padrão de IMFAsyncResult bloqueia automaticamente a plataforma media foundation quando o objeto de resultado é criado. Liberar a interface desbloqueia a plataforma. Portanto, você quase nunca precisará bloquear a plataforma diretamente. Mas se você escrever sua própria implementação personalizada de IMFAsyncResult, deverá bloquear e desbloquear manualmente a plataforma. Para bloquear a plataforma, chame MFLockPlatform. Para desbloquear a plataforma, chame MFUnlockPlatform. Para obter um exemplo, consulte Objetos de resultado assíncronos personalizados.

Depois de chamar MFShutdown, você precisa garantir que a plataforma seja desbloqueada dentro do período de tempo limite de 5 segundos. Faça isso liberando todos os ponteiros IMFAsyncResult e chamando MFUnlockPlatform se você bloqueou a plataforma manualmente. Certifique-se de liberar todos os recursos que estão sendo usados por threads de fila de trabalho ou seu aplicativo pode vazar memória.

Normalmente, se o aplicativo for desligado e liberar todos os objetos do Media Foundation antes de chamar o MFShutdown, você não precisará se preocupar com o bloqueio. O mecanismo de bloqueio simplesmente permite que os threads de fila de trabalho saiam normalmente depois que você chama MFShutdown.

Usando itens de trabalho agendados

Você pode agendar um retorno de chamada para ocorrer após um período definido chamando MFScheduleWorkItem ou MFScheduleWorkItemEx.

  • MFScheduleWorkItem usa um ponteiro para o retorno de chamada, um objeto de estado opcional e um intervalo de tempo limite.
  • MFScheduleWorkItemEx usa um ponteiro para um objeto de resultado assíncrono e um valor de tempo limite.

Especifique o tempo limite como um valor negativo em milissegundos. Por exemplo, para agendar um retorno de chamada a ser invocado em 5 segundos, use o valor −5000. Ambas as funções retornam um valor MFWORKITEM_KEY , que você pode usar para cancelar o retorno de chamada passando-o para a função MFCancelWorkItem .

Os itens de trabalho agendados sempre usam a fila de trabalho da plataforma MFASYNC_CALLBACK_QUEUE_TIMER.

Usando retornos de chamada periódicos

A função MFAddPeriodicCallback agenda um retorno de chamada a ser invocado periodicamente até que você o cancele. O intervalo de retorno de chamada é fixo; os aplicativos não podem alterá-lo. Para descobrir o intervalo exato, chame MFGetTimerPeriodicity. O intervalo está na ordem de 10 milissegundos, portanto, essa função destina-se a situações em que você precisa de um "tique" frequente, como implementar um relógio de apresentação. Se você quiser agendar uma operação para ocorrer com menos frequência, use um item de trabalho agendado, conforme descrito anteriormente.

Ao contrário dos outros retornos de chamada descritos neste tópico, o retorno de chamada periódico não usa a interface IMFAsyncCallback . Em vez disso, ele usa um ponteiro de função. Para obter mais informações, consulte Retorno de chamada MFPERIODICCALLBACK.

Para cancelar o retorno de chamada periódico, chame MFRemovePeriodicCallback.

Retornos de chamada periódicos usam a fila de trabalho da plataforma MFASYNC_CALLBACK_QUEUE_TIMER.

Filas de Trabalho

MFASYNCRESULT

Melhorias na fila de trabalho e no threading