Utilisation de files d’attente de travail

Cette rubrique explique comment utiliser des files d’attente de travail dans Microsoft Media Foundation.

Utilisation de files d’attente de travail

Une file d’attente de travail est un moyen efficace d’effectuer des opérations asynchrones sur un autre thread. D’un point de vue conceptuel, vous placez des éléments de travail dans la file d’attente, et la file d’attente a un thread qui extrait chaque élément de la file d’attente et le distribue. Les éléments de travail sont implémentés en tant que rappels à l’aide de l’interface IMFAsyncCallback .

Media Foundation crée plusieurs files d’attente de travail standard, appelées files d’attente de travail de plateforme. Les applications peuvent également créer leurs propres files d’attente de travail, appelées files d’attente de travail privées. Pour obtenir la liste des files d’attente de travail de la plateforme, consultez Identificateurs de file d’attente de travail. Pour créer une file d’attente de travail privée, appelez MFAllocateWorkQueue. Cette fonction retourne un identificateur pour la nouvelle file d’attente de travail. Pour placer un élément dans la file d’attente, appelez MFPutWorkItem ou MFPutWorkItemEx. Dans les deux cas, vous devez spécifier une interface de rappel.

  • MFPutWorkItem prend un pointeur vers l’interface IMFAsyncCallback , ainsi qu’un objet d’état facultatif qui implémente IUnknown. Il s’agit des mêmes paramètres que ceux utilisés dans les méthodes asynchrones, comme décrit dans la rubrique Méthodes de rappel asynchrones. En interne, cette fonction crée un objet de résultat asynchrone, qui est passé à la méthode Invoke du rappel.
  • MFPutWorkItemEx prend un pointeur vers l’interface IMFAsyncResult . Cette interface représente un objet de résultat asynchrone. Créez cet objet en appelant MFCreateAsyncResult et en spécifiant votre interface de rappel et, éventuellement, un objet d’état.

Dans les deux cas, le thread de file d’attente de travail appelle votre méthode IMFAsyncCallback::Invoke . Utilisez la méthode Invoke pour effectuer l’élément de travail.

Si plusieurs threads ou composants partagent la même file d’attente de travail, vous pouvez appeler MFLockWorkQueue pour verrouiller la file d’attente de travail, ce qui empêche la plateforme de la libérer. Pour chaque appel à MFAllocateWorkQueue ou MFLockWorkQueue, vous devez appeler MFUnlockWorkQueue une fois pour libérer la file d’attente de travail. Par exemple, si vous créez une file d’attente de travail et que vous la verrouillez une fois, vous devez appeler MFUnlockWorkQueue deux fois, une fois pour l’appel à MFAllocateWorkQueue et une fois pour l’appel à MFLockWorkQueue.

Le code suivant montre comment créer une file d’attente de travail, placer un élément de travail dans la file d’attente et libérer la file d’attente de travail.

Pour plus d’informations sur les files d’attente de travail dans Windows 8, consultez Améliorations apportées à la file d’attente de travail et au threading.

DWORD idWorkQueue = 0;
HRESULT hr = S_OK;

// Create a new work queue.
hr = MFAllocateWorkQueue(&idWorkQueue);

// Put an item on the queue.
if (SUCCEEDED(hr))
{
    hr = MFPutWorkItem(idWorkQueue, pCallback, NULL);
}

// Wait for the callback to be invoked.
if (SUCCEEDED(hr))
{
    WaitForSingleObject(hEvent, INFINITE);
}

// Release the work queue.
if (SUCCEEDED(hr))
{
    hr = MFUnlockWorkQueue(idWorkQueue);
}

Cet exemple suppose que pCallback est un pointeur vers l’interface IMFAsyncCallback de l’application. Il part également du principe que le rappel définit le handle d’événement hEvent . Le code attend que cet événement soit défini avant d’appeler MFUnlockWorkQueue.

Les threads de file d’attente de travail sont toujours créés dans le processus de l’appelant. Dans chaque file d’attente de travail, les rappels sont sérialisés. Si vous appelez MFPutWorkItem deux fois avec la même file d’attente de travail, le deuxième rappel n’est pas appelé tant que le premier rappel n’est pas retourné.

Arrêt des files d’attente de travail

Avant d’appeler MFShutdown, libérez toutes les ressources utilisées par les threads de file d’attente de travail. Pour synchroniser ce processus, vous pouvez verrouiller la plateforme Media Foundation, ce qui empêche la fonction MFShutdown de fermer les threads de file d’attente de travail. Si MFShutdown est appelé alors que la plateforme est verrouillée, MFShutdown attend quelques centaines de millisecondes pour que la plateforme soit déverrouillée. S’il n’est pas déverrouillé dans ce délai, MFShutdown ferme les threads de file d’attente de travail.

L’implémentation par défaut d’IMFAsyncResult verrouille automatiquement la plateforme Media Foundation lors de la création de l’objet de résultat. La libération de l’interface déverrouille la plateforme. Par conséquent, vous n’aurez presque jamais besoin de verrouiller directement la plateforme. Toutefois, si vous écrivez votre propre implémentation personnalisée d’IMFAsyncResult, vous devez verrouiller et déverrouiller manuellement la plateforme. Pour verrouiller la plateforme, appelez MFLockPlatform. Pour déverrouiller la plateforme, appelez MFUnlockPlatform. Pour obtenir un exemple, consultez Objets de résultats asynchrones personnalisés.

Après avoir appelé MFShutdown, vous devez vous assurer que la plateforme est déverrouillée dans le délai d’attente de 5 secondes. Pour ce faire, relâchez tous les pointeurs IMFAsyncResult et appelez MFUnlockPlatform si vous avez verrouillé la plateforme manuellement. Veillez à libérer toutes les ressources utilisées par les threads de file d’attente de travail, sinon votre application risque de fuite de mémoire.

En règle générale, si votre application s’arrête et libère chaque objet Media Foundation avant d’appeler MFShutdown, vous n’avez pas à vous soucier du verrouillage. Le mécanisme de verrouillage permet simplement aux threads de file d’attente de travail de se fermer correctement après avoir appelé MFShutdown.

Utilisation d’éléments de travail planifiés

Vous pouvez planifier un rappel après une période définie en appelant MFScheduleWorkItem ou MFScheduleWorkItemEx.

  • MFScheduleWorkItem prend un pointeur vers votre rappel, un objet d’état facultatif et un intervalle de délai d’attente.
  • MFScheduleWorkItemEx prend un pointeur vers un objet de résultat asynchrone et une valeur de délai d’attente.

Spécifiez le délai d’attente sous la forme d’une valeur négative en millisecondes. Par exemple, pour planifier un rappel à appeler en 5 secondes, utilisez la valeur −5000. Les deux fonctions retournent une valeur MFWORKITEM_KEY , que vous pouvez utiliser pour annuler le rappel en la transmettant à la fonction MFCancelWorkItem .

Les éléments de travail planifiés utilisent toujours la file d’attente de travail MFASYNC_CALLBACK_QUEUE_TIMER plateforme.

Utilisation de rappels périodiques

La fonction MFAddPeriodicCallback planifie un rappel à appeler régulièrement jusqu’à ce que vous l’annuliez. L’intervalle de rappel est fixe ; les applications ne peuvent pas la modifier. Pour connaître l’intervalle exact, appelez MFGetTimerPeriodicity. L’intervalle étant de l’ordre de 10 millisecondes, cette fonction est destinée aux situations où vous avez besoin d’une « graduation » fréquente, comme l’implémentation d’une horloge de présentation. Si vous souhaitez planifier une opération pour qu’elle se produise moins fréquemment, utilisez un élément de travail planifié, comme décrit précédemment.

Contrairement aux autres rappels décrits dans cette rubrique, le rappel périodique n’utilise pas l’interface IMFAsyncCallback . Au lieu de cela, il utilise un pointeur de fonction. Pour plus d’informations, consultez Rappel MFPERIODICCALLBACK.

Pour annuler le rappel périodique, appelez MFRemovePeriodicCallback.

Les rappels périodiques utilisent la file d’attente de travail MFASYNC_CALLBACK_QUEUE_TIMER plateforme.

Files d’attente de travail

MFASYNCRESULT

Améliorations apportées à la file d’attente de travail et au threading