Appeler des méthodes asynchrones
Dans Media Foundation, de nombreuses opérations sont exécutées de façon asynchrone. Les opérations asynchrones peuvent améliorer les performances, car elles ne bloquent pas le thread appelant. Une opération asynchrone dans Media Foundation est définie par une paire de méthodes avec la Convention d’affectation de noms Begin.. . et end.... Ensemble, ces deux méthodes définissent une opération de lecture asynchrone sur le flux.
Pour démarrer une opération asynchrone, appelez la méthode Begin . La méthode Begin contient toujours au moins deux paramètres :
- Pointeur vers l’interface IMFAsyncCallback . L’application doit implémenter cette interface.
- Pointeur vers un objet d’État facultatif.
L’interface IMFAsyncCallback avertit l’application lorsque l’opération est terminée. Pour obtenir un exemple d’implémentation de cette interface, consultez implémentation du rappel asynchrone. L’objet d’État est facultatif. S’il est spécifié, il doit implémenter l’interface IUnknown . Vous pouvez utiliser l’objet d’État pour stocker toutes les informations d’État requises par votre rappel. Si vous n’avez pas besoin d’informations d’État, vous pouvez définir ce paramètre sur la valeur null. La méthode Begin peut contenir des paramètres supplémentaires qui sont spécifiques à cette méthode.
Si la méthode Begin retourne un code d’échec, cela signifie que l’opération a échoué immédiatement et que le rappel n’est pas appelé. Si la méthode Begin réussit, cela signifie que l’opération est en attente et que le rappel est appelé lorsque l’opération se termine.
Par exemple, la méthode IMFByteStream :: BeginRead démarre une opération de lecture asynchrone sur un flux d’octets :
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);
}
La méthode de rappel est IMFAsyncCallback :: Invoke. Il possède un seul paramètre, pAsyncResult, qui est un pointeur vers l’interface IMFAsyncResult . Pour terminer l’opération asynchrone, appelez la méthode end qui correspond à la méthode Begin asynchrone. La méthode end prend toujours un pointeur IMFAsyncResult . Transmettez toujours le même pointeur que celui que vous avez reçu dans la méthode Invoke . L’opération asynchrone n’est pas terminée tant que vous n’avez pas appelé la méthode end . Vous pouvez appeler la méthode end à partir de la méthode Invoke , ou vous pouvez l’appeler à partir d’un autre thread.
Par exemple, pour terminer IMFByteStream :: BeginRead sur un flux d’octets, appelez IMFByteStream :: EndRead:
STDMETHODIMP Invoke(IMFAsyncResult* pResult)
{
m_hrStatus = m_pStream->EndRead(pResult, &m_cbRead);
SetEvent(m_hEvent);
return S_OK;
}
La valeur de retour de la méthode end indique l’état de l’opération asynchrone. Dans la plupart des cas, votre application effectue un travail après l’exécution de l’opération asynchrone, qu’elle se termine correctement ou non. Vous disposez de plusieurs options :
- Effectuez le travail à l’intérieur de la méthode Invoke . Cette approche est acceptable tant que votre application ne bloque jamais le thread appelant ou n’attend rien à l’intérieur de la méthode Invoke . Si vous bloquez le thread appelant, vous risquez de bloquer le pipeline de diffusion en continu. Par exemple, vous pouvez mettre à jour certaines variables d’État, mais n’effectuez pas d’opération de lecture synchrone ou d’attente sur un objet Mutex.
- Dans la méthode Invoke , définissez un événement et retournez immédiatement. Le thread appelant de l’application attend l’événement et effectue le travail lorsque l’événement est signalé.
- Dans la méthode Invoke , publiez un message de fenêtre privée dans la fenêtre de votre application et revenez immédiatement. L’application effectue le travail sur sa boucle de message. (Veillez à poster le message en appelant PostMessage, et non SendMessage, car SendMessage peut bloquer le thread de rappel.)
Il est important de se souvenir que Invoke est appelé à partir d’un autre thread. Votre application est chargée de s’assurer que tout travail effectué dans Invoke est thread-safe.
Par défaut, le thread qui appelle Invoke n’émet aucune hypothèse sur le comportement de votre objet de rappel. Si vous le souhaitez, vous pouvez implémenter la méthode IMFAsyncCallback :: GetParameters pour retourner des informations sur votre implémentation de rappel. Sinon, cette méthode peut retourner E _ NOTIMPL:
STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue)
{
// Implementation of this method is optional.
return E_NOTIMPL;
}
Si vous avez spécifié un objet d’État dans la méthode Begin , vous pouvez le récupérer à l’intérieur de votre méthode de rappel en appelant IMFAsyncResult :: GetState.