Chamando métodos assíncronos
No Media Foundation, muitas operações são executadas de forma assíncrona. As operações assíncronas podem melhorar o desempenho, pois não bloqueiam o thread de chamada. Uma operação assíncrona no Media Foundation é definida por um par de métodos com a convenção de nomenclatura Begin... e End..... Juntos, esses dois métodos definem uma operação de leitura assíncrona no fluxo.
Para iniciar uma operação assíncrona, chame o método Begin . O método Begin sempre contém pelo menos dois parâmetros:
- Um ponteiro para a interface IMFAsyncCallback . O aplicativo deve implementar essa interface.
- Um ponteiro para um objeto de estado opcional.
A interface IMFAsyncCallback notifica o aplicativo quando a operação é concluída. Para obter um exemplo de como implementar essa interface, consulte Implementando o retorno de chamada assíncrono. O objeto state é opcional. Se especificado, ele deve implementar a interface IUnknown . Você pode usar o objeto state para armazenar todas as informações de estado necessárias para o retorno de chamada. Se você não precisar de informações de estado, poderá definir esse parâmetro como NULL. O método Begin pode conter parâmetros adicionais específicos a esse método.
Se o método Begin retornar um código de falha, isso significa que a operação falhou imediatamente e o retorno de chamada não será invocado. Se o método Begin for bem-sucedido, isso significa que a operação está pendente e o retorno de chamada será invocado quando a operação for concluída.
Por exemplo, o método IMFByteStream::BeginRead inicia uma operação de leitura assíncrona em um fluxo de bytes:
BYTE data[DATA_SIZE];
ULONG cbRead = 0;
CMyCallback *pCB = new (std::nothrow) CMyCallback(pStream, &hr);
if (pCB == NULL)
{
hr = E_OUTOFMEMORY;
}
// Start an asynchronous request to read data.
if (SUCCEEDED(hr))
{
hr = pStream->BeginRead(data, DATA_SIZE, pCB, NULL);
}
O método de retorno de chamada é IMFAsyncCallback::Invoke. Ele tem um único parâmetro, pAsyncResult, que é um ponteiro para a interface IMFAsyncResult . Para concluir a operação assíncrona, chame o método End que corresponde ao método Begin assíncrono. O método End sempre usa um ponteiro IMFAsyncResult . Sempre passe o mesmo ponteiro que você recebeu no método Invoke . A operação assíncrona não é concluída até que você chame o método End . Você pode chamar o método End de dentro do método Invoke ou chamá-lo de outro thread.
Por exemplo, para concluir o IMFByteStream::BeginRead em um fluxo de bytes, chame IMFByteStream::EndRead:
STDMETHODIMP Invoke(IMFAsyncResult* pResult)
{
m_hrStatus = m_pStream->EndRead(pResult, &m_cbRead);
SetEvent(m_hEvent);
return S_OK;
}
O valor retornado do método End indica o status da operação assíncrona. Na maioria dos casos, seu aplicativo executará algum trabalho após a conclusão da operação assíncrona, seja ela concluída com êxito ou não. Você tem várias opções:
- Faça o trabalho dentro do método Invoke . Essa abordagem é aceitável, desde que seu aplicativo nunca bloqueie o thread de chamada ou aguarde qualquer coisa dentro do método Invoke . Se você bloquear o thread de chamada, poderá bloquear o pipeline de streaming. Por exemplo, você pode atualizar algumas variáveis de estado, mas não executar uma operação de leitura síncrona ou aguardar em um objeto mutex.
- No método Invoke , defina um evento e retorne imediatamente. O thread de chamada do aplicativo aguarda o evento e faz o trabalho quando o evento é sinalizado.
- No método Invoke , poste uma mensagem de janela privada na janela do aplicativo e retorne imediatamente. O aplicativo faz o trabalho em seu loop de mensagem. (Certifique-se de postar a mensagem chamando PostMessage, não SendMessage, porque SendMessage pode bloquear o thread de retorno de chamada.)
É importante lembrar que Invoke é chamado de outro thread. Seu aplicativo é responsável por garantir que qualquer trabalho executado dentro do Invoke seja thread-safe.
Por padrão, o thread que chama Invoke não faz suposições sobre o comportamento do objeto de retorno de chamada. Opcionalmente, você pode implementar o método IMFAsyncCallback::GetParameters para retornar informações sobre sua implementação de retorno de chamada. Caso contrário, esse método poderá retornar E_NOTIMPL:
STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
// Implementation of this method is optional.
return E_NOTIMPL;
}
Se você especificou um objeto de estado no método Begin , poderá recuperá-lo de dentro do método de retorno de chamada chamando IMFAsyncResult::GetState.
Tópicos relacionados