Condividi tramite


Chiamata di metodi asincroni

In Media Foundation vengono eseguite molte operazioni in modo asincrono. Le operazioni asincrone possono migliorare le prestazioni, perché non bloccano il thread chiamante. Un'operazione asincrona in Media Foundation è definita da una coppia di metodi con la convenzione di denominazione Begin... e End..... Insieme, questi due metodi definiscono un'operazione di lettura asincrona nel flusso.

Per avviare un'operazione asincrona, chiamare il metodo Begin . Il metodo Begin contiene sempre almeno due parametri:

  • Puntatore all'interfaccia IMFAsyncCallback . L'applicazione deve implementare questa interfaccia.
  • Puntatore a un oggetto stato facoltativo.

L'interfaccia IMFAsyncCallback notifica all'applicazione al termine dell'operazione. Per un esempio di come implementare questa interfaccia, vedere Implementazione del callback asincrono. L'oggetto state è facoltativo. Se specificato, deve implementare l'interfaccia IUnknown . È possibile usare l'oggetto state per archiviare qualsiasi informazione sullo stato necessaria dal callback. Se non sono necessarie informazioni sullo stato, è possibile impostare questo parametro su NULL. Il metodo Begin potrebbe contenere parametri aggiuntivi specifici di tale metodo.

Se il metodo Begin restituisce un codice di errore, significa che l'operazione non è riuscita immediatamente e il callback non verrà richiamato. Se il metodo Begin ha esito positivo, significa che l'operazione è in sospeso e il callback verrà richiamato al termine dell'operazione.

Ad esempio, il metodo IMFByteStream::BeginRead avvia un'operazione di lettura asincrona in un flusso di byte:

    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);
    }

Il metodo callback è FMAsyncCallback::Invoke. Ha un singolo parametro, pAsyncResult, che è un puntatore all'interfaccia IMFAsyncResult . Per completare l'operazione asincrona, chiamare il metodo End che corrisponde al metodo Begin asincrono. Il metodo End accetta sempre un puntatore IMFAsyncResult . Passare sempre lo stesso puntatore ricevuto nel metodo Invoke . L'operazione asincrona non viene completata finché non si chiama il metodo End . È possibile chiamare il metodo End dall'interno del metodo Invoke oppure chiamarlo da un altro thread.

Ad esempio, per completare l'FMByteStream::BeginRead in un flusso di byte, chiamare FMByteStream::EndRead:

    STDMETHODIMP Invoke(IMFAsyncResult* pResult)
    {
        m_hrStatus = m_pStream->EndRead(pResult, &m_cbRead);

        SetEvent(m_hEvent);

        return S_OK;
    }

Il valore restituito del metodo End indica lo stato dell'operazione asincrona. Nella maggior parte dei casi, l'applicazione eseguirà alcune operazioni dopo il completamento dell'operazione asincrona, indipendentemente dal completamento o meno. Sono disponibili diverse opzioni:

  • Eseguire il lavoro all'interno del metodo Invoke . Questo approccio è accettabile finché l'applicazione non blocca mai il thread chiamante o attende qualsiasi elemento all'interno del metodo Invoke . Se si blocca il thread chiamante, è possibile bloccare la pipeline di streaming. Ad esempio, è possibile aggiornare alcune variabili di stato, ma non eseguire un'operazione di lettura sincrona o attendere su un oggetto mutex.
  • Nel metodo Invoke impostare un evento e restituire immediatamente. Il thread chiamante dell'applicazione attende l'evento e esegue il funzionamento quando l'evento viene segnalato.
  • Nel metodo Invoke pubblicare un messaggio di finestra privata nella finestra dell'applicazione e restituire immediatamente. L'applicazione esegue il funzionamento del ciclo di messaggi. Assicurarsi di pubblicare il messaggio chiamando PostMessage, non SendMessage, perché SendMessage può bloccare il thread di callback.

È importante ricordare che Invoke viene chiamato da un altro thread. L'applicazione è responsabile della garanzia che qualsiasi lavoro eseguito all'interno di Invoke sia thread-safe.

Per impostazione predefinita, il thread che chiama Invoke non presuppone il comportamento dell'oggetto callback. Facoltativamente, è possibile implementare il metodo IMFAsyncCallback::GetParameters per restituire informazioni sull'implementazione del callback. In caso contrario, questo metodo può restituire E_NOTIMPL:

    STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
    {
        // Implementation of this method is optional.
        return E_NOTIMPL;
    }

Se è stato specificato un oggetto stato nel metodo Begin , è possibile recuperarlo dall'interno del metodo di callback chiamando FMAsyncResult::GetState.

Metodi di callback asincroni