Condividi tramite


Uso delle code di lavoro

Questo argomento descrive come usare le code di lavoro in Microsoft Media Foundation.

Uso delle code di lavoro

Una coda di lavoro è un modo efficiente per eseguire operazioni asincrone su un altro thread. Concettualmente, inserire gli elementi di lavoro nella coda e la coda ha un thread che esegue il pull di ogni elemento dalla coda e lo invia. Gli elementi di lavoro vengono implementati come callback tramite l'interfaccia IMFAsyncCallback .

Media Foundation crea diverse code di lavoro standard, denominate code di lavoro della piattaforma. Le applicazioni possono anche creare code di lavoro personalizzate, denominate code di lavoro private. Per un elenco delle code di lavoro della piattaforma, vedere Identificatori della coda di lavoro. Per creare una coda di lavoro privata, chiamare MFAllocateWorkQueue. Questa funzione restituisce un identificatore per la nuova coda di lavoro. Per inserire un elemento nella coda, chiamare MFPutWorkItem o MFPutWorkItemEx. In entrambi i casi, è necessario specificare un'interfaccia di callback.

  • MFPutWorkItem accetta un puntatore all'interfaccia IMFAsyncCallback , oltre a un oggetto di stato facoltativo che implementa IUnknown. Si tratta degli stessi parametri usati nei metodi asincroni, come descritto nell'argomento Metodi di callback asincroni. Internamente, questa funzione crea un oggetto risultato asincrono, che viene passato al metodo Invoke del callback.
  • MFPutWorkItemEx accetta un puntatore all'interfaccia IMFAsyncResult . Questa interfaccia rappresenta un oggetto risultato asincrono. Creare questo oggetto chiamando MFCreateAsyncResult e specificando l'interfaccia di callback e, facoltativamente, un oggetto stato.

In entrambi i casi, il thread della coda di lavoro chiama il metodo IMFAsyncCallback::Invoke . Utilizzare il metodo Invoke per eseguire l'elemento di lavoro.

Se più thread o componenti condividono la stessa coda di lavoro, è possibile chiamare MFLockWorkQueue per bloccare la coda di lavoro, impedendo così alla piattaforma di rilasciarla. Per ogni chiamata a MFAllocateWorkQueue o MFLockWorkQueue, è necessario chiamare MFUnlockWorkQueue una volta per rilasciare la coda di lavoro. Ad esempio, se si crea una nuova coda di lavoro e quindi la si blocca una sola volta, è necessario chiamare MFUnlockWorkQueue due volte, una volta per la chiamata a MFAllocateWorkQueue e una volta per la chiamata a MFLockWorkQueue.

Il codice seguente illustra come creare una nuova coda di lavoro, inserire un elemento di lavoro nella coda e rilasciare la coda di lavoro.

Per altre informazioni sulle code di lavoro in Windows 8, vedere Miglioramenti alla coda di lavoro e al 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);
}

Questo esempio presuppone che pCallback sia un puntatore all'interfaccia IMFAsyncCallback dell'applicazione. Presuppone inoltre che il callback imposti l'handle dell'evento hEvent . Il codice attende che questo evento venga impostato prima di chiamare MFUnlockWorkQueue.

I thread della coda di lavoro vengono sempre creati nel processo del chiamante. All'interno di ogni coda di lavoro, i callback vengono serializzati. Se si chiama MFPutWorkItem due volte con la stessa coda di lavoro, il secondo callback non viene richiamato fino a quando non viene restituito il primo callback.

Arresto delle code di lavoro

Prima di chiamare MFShutdown, rilasciare tutte le risorse usate dai thread della coda di lavoro. Per sincronizzare questo processo, è possibile bloccare la piattaforma Media Foundation, che impedisce alla funzione MFShutdown di chiudere qualsiasi thread della coda di lavoro. Se MFShutdown viene chiamato mentre la piattaforma è bloccata, MFShutdown attende qualche centinaio di millisecondi affinché la piattaforma venga sbloccata. Se non viene sbloccato entro tale tempo, MFShutdown chiude i thread della coda di lavoro.

L'implementazione predefinita di IMFAsyncResult blocca automaticamente la piattaforma Media Foundation quando viene creato l'oggetto risultato. Il rilascio dell'interfaccia sblocca la piattaforma. Pertanto, quasi mai sarà necessario bloccare direttamente la piattaforma. Tuttavia, se scrivi la tua implementazione personalizzata di IMFAsyncResult, devi bloccare e sbloccare manualmente la piattaforma. Per bloccare la piattaforma, chiamare MFLockPlatform. Per sbloccare la piattaforma, chiama MFUnlockPlatform. Per un esempio, vedere Oggetti risultato asincroni personalizzati.

Dopo aver chiamato MFShutdown, è necessario assicurarsi che la piattaforma venga sbloccata entro il periodo di timeout di 5 secondi. A tale scopo, rilasciare tutti i puntatori IMFAsyncResult e chiamando MFUnlockPlatform se la piattaforma è stata bloccata manualmente. Assicurarsi di rilasciare tutte le risorse usate dai thread della coda di lavoro o che l'applicazione potrebbe perdere memoria.

In genere, se l'applicazione si arresta e rilascia ogni oggetto Media Foundation prima di chiamare MFShutdown, non è necessario preoccuparsi del blocco. Il meccanismo di blocco consente semplicemente ai thread della coda di lavoro di uscire normalmente dopo aver chiamato MFShutdown.

Uso di elementi di lavoro pianificati

È possibile pianificare un callback dopo un periodo di tempo impostato chiamando MFScheduleWorkItem o MFScheduleWorkItemEx.

  • MFScheduleWorkItem accetta un puntatore al callback, un oggetto stato facoltativo e un intervallo di timeout.
  • MFScheduleWorkItemEx accetta un puntatore a un oggetto risultato asincrono e un valore di timeout.

Specificare il timeout come valore negativo in millisecondi. Ad esempio, per pianificare un callback da richiamare in 5 secondi, usare il valore −5000. Entrambe le funzioni restituiscono un valore MFWORKITEM_KEY , che è possibile usare per annullare il callback passandolo alla funzione MFCancelWorkItem .

Gli elementi di lavoro pianificati usano sempre la coda di lavoro della piattaforma MFASYNC_CALLBACK_QUEUE_TIMER.

Uso di callback periodici

La funzione MFAddPeriodicCallback pianifica periodicamente un callback da richiamare finché non viene annullata. L'intervallo di callback è fisso; le applicazioni non possono modificarle. Per scoprire l'intervallo esatto, chiama MFGetTimerPeriodicity. L'intervallo è in ordine di 10 millisecondi, quindi questa funzione è destinata a situazioni in cui è necessario un "tick" frequente, ad esempio l'implementazione di un orologio di presentazione. Se si vuole pianificare un'operazione con una frequenza minore, usare un elemento di lavoro pianificato, come descritto in precedenza.

A differenza degli altri callback descritti in questo argomento, il callback periodico non usa l'interfaccia IMFAsyncCallback . Usa invece un puntatore a funzione. Per altre informazioni, vedere Callback MFPERIODICCALLBACK.

Per annullare il callback periodico, chiamare MFRemovePeriodicCallback.

I callback periodici usano la coda di lavoro della piattaforma MFASYNC_CALLBACK_QUEUE_TIMER.

Code di lavoro

MFASYNCRESULT

Miglioramenti alla coda di lavoro e al threading