Вызов асинхронных методов
В Media Foundation многие операции выполняются асинхронно. Асинхронные операции могут повысить производительность, так как они не блокируют вызывающий поток. Асинхронная операция в Media Foundation определяется парой методов с соглашением об именовании Begin... и End..... Вместе эти два метода определяют асинхронную операцию чтения в потоке.
Чтобы запустить асинхронную операцию, вызовите метод Begin . Метод Begin всегда содержит по крайней мере два параметра:
- Указатель на интерфейс IMFAsyncCallback . Приложение должно реализовать этот интерфейс.
- Указатель на необязательный объект состояния.
Интерфейс IMFAsyncCallback уведомляет приложение о завершении операции. Пример реализации этого интерфейса см. в разделе Реализация асинхронного обратного вызова. Объект состояния необязателен. Если он указан, он должен реализовывать интерфейс IUnknown . Объект состояния можно использовать для хранения любых сведений о состоянии, необходимых для обратного вызова. Если сведения о состоянии не требуются, можно задать для этого параметра значение NULL. Метод Begin может содержать дополнительные параметры, относящиеся к конкретному методу.
Если метод Begin возвращает код сбоя, это означает, что операция завершилась сбоем немедленно, и обратный вызов не будет вызван. Если метод Begin завершается успешно, это означает, что операция находится в состоянии ожидания, а обратный вызов будет вызван после завершения операции.
Например, метод IMFByteStream::BeginRead запускает асинхронную операцию чтения в потоке байтов:
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);
}
Метод обратного вызова — IMFAsyncCallback::Invoke. Он имеет один параметр pAsyncResult, который является указателем на интерфейс IMFAsyncResult . Чтобы завершить асинхронную операцию, вызовите метод End , соответствующий асинхронным методу Begin . Метод End всегда принимает указатель IMFAsyncResult . Всегда передайте тот же указатель, который вы получили в методе Invoke . Асинхронная операция не будет завершена, пока вы не вызовете метод End . Метод End можно вызвать из метода Invoke или из другого потока.
Например, чтобы завершить IMFByteStream::BeginRead в потоке байтов, вызовите IMFByteStream::EndRead:
STDMETHODIMP Invoke(IMFAsyncResult* pResult)
{
m_hrStatus = m_pStream->EndRead(pResult, &m_cbRead);
SetEvent(m_hEvent);
return S_OK;
}
Возвращаемое значение метода End указывает состояние асинхронной операции. В большинстве случаев приложение выполняет определенную работу после завершения асинхронной операции, независимо от того, успешно ли она выполнена или нет. Доступно несколько параметров.
- Выполните работу в методе Invoke . Такой подход допустим, если приложение никогда не блокирует вызывающий поток или не ожидает чего-либо в методе Invoke . Если вы заблокируйте вызывающий поток, вы можете заблокировать конвейер потоковой передачи. Например, можно обновить некоторые переменные состояния, но не выполнять синхронную операцию чтения или ждать объекта мьютекса.
- В методе Invoke задайте событие и немедленно вернитесь. Вызывающий поток приложения ожидает события и выполняет работу при сигнале о событии.
- В методе Invoke опубликуйте сообщение закрытого окна в окне приложения и немедленно вернитесь. Приложение выполняет работу со своим циклом сообщений. (Обязательно опубликуйте сообщение, вызвав PostMessage, а не SendMessage, так как SendMessage может заблокировать поток обратного вызова.)
Важно помнить, что invoke вызывается из другого потока. Ваше приложение отвечает за то, чтобы все операции, выполняемые внутри Invoke , были потокобезопасны.
По умолчанию поток, вызывающий Invoke , не делает никаких предположений о поведении объекта обратного вызова. При необходимости можно реализовать метод IMFAsyncCallback::GetParameters , чтобы получить сведения о реализации обратного вызова. В противном случае этот метод может возвращать E_NOTIMPL:
STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
// Implementation of this method is optional.
return E_NOTIMPL;
}
Если вы указали объект состояния в методе Begin , его можно получить из метода обратного вызова, вызвав IMFAsyncResult::GetState.
Связанные темы