Share via


呼叫非同步方法

在媒體基礎中,許多作業都是以非同步方式執行。 非同步作業可以改善效能,因為它們不會封鎖呼叫執行緒。 媒體基礎中的非同步作業是由一對方法所定義,其命名慣例 為 Begin...End....。 這兩種方法會一起定義資料流程上的非同步讀取作業。

若要啟動非同步作業,請呼叫 Begin 方法。 Begin方法一律包含至少兩個參數:

  • IMFAsyncCallback介面的指標。 應用程式必須實作這個介面。
  • 選擇性狀態物件的指標。

IMFAsyncCallback介面會在作業完成時通知應用程式。 如需如何實作此介面的範例,請參閱 實作非同步回呼。 狀態物件是選擇性的。 如果指定,它必須實作 IUnknown 介面。 您可以使用狀態物件來儲存回呼所需的任何狀態資訊。 如果您不需要狀態資訊,您可以將此參數設定為 NullBegin方法可能包含該方法特有的其他參數。

如果 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 介面的指標。 若要完成非同步作業,請呼叫符合非同步Begin方法的End方法。 End方法一律會採用IMFAsyncResult指標。 一律傳入您在 Invoke 方法中收到的相同指標。 除非您呼叫 End 方法,否則非同步作業不會完成。 您可以從Invoke方法內呼叫End方法,也可以從另一個執行緒呼叫它。

例如,若要在位元組資料流程上完成 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 方法內的任何專案,這個方法就可接受。 如果您封鎖呼叫執行緒,您可能會封鎖串流管線。 例如,您可能會更新某些狀態變數,但不會執行同步讀取作業,或等候 mutex 物件。
  • Invoke 方法中,設定事件並立即傳回。 應用程式的呼叫執行緒會等候事件,並在事件發出訊號時執行工作。
  • Invoke 方法中,將私人視窗訊息張貼至您的應用程式視窗並立即傳回。 應用程式會在其訊息迴圈上執行工作。 (請務必呼叫PostMessage 而非 SendMessage來張貼訊息,因為SendMessage可以封鎖回呼 thread.)

請務必記住,從另一個執行緒呼叫 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,從回呼方法內擷取它。

非同步回呼方法