作業キューの使用
このトピックでは、Microsoft Media Foundation で作業キューを使用する方法について説明します。
作業キューの使用
作業キューは、別のスレッドで非同期操作を実行する効率的な方法です。 概念的には、作業項目をキューに配置し、キューにはキューから各項目をプルしてディスパッチするスレッドがあります。 作業項目は、 IMFAsyncCallback インターフェイスを使用してコールバックとして実装されます。
Media Foundation では、プラットフォーム作業キューと呼ばれるいくつかの標準 作業キューが作成されます。 アプリケーションは、プライベート作業キューと呼ばれる独自の 作業キューを作成することもできます。 プラットフォーム作業キューの一覧については、「 作業キュー識別子」を参照してください。 プライベート作業キューを作成するには、 MFAllocateWorkQueue を呼び出します。 この関数は、新しい作業キューの識別子を返します。 キューに項目を配置するには、 MFPutWorkItem または MFPutWorkItemEx を呼び出します。 どちらの場合も、コールバック インターフェイスを指定する必要があります。
- MFPutWorkItem は、 IMFAsyncCallback インターフェイスへのポインターと、 IUnknown を実装する省略可能な状態オブジェクトを受け取ります。 これらは、非同期メソッドで使用されるパラメーターと同じです。「 非同期コールバック メソッド」のトピックで説明します。 内部的には、この関数はコールバックの Invoke メソッドに渡される非同期の結果オブジェクトを作成します。
- MFPutWorkItemEx は、 IMFAsyncResult インターフェイスへのポインターを受け取ります。 このインターフェイスは、非同期の結果オブジェクトを表します。 このオブジェクトを作成するには 、MFCreateAsyncResult を呼び出し、コールバック インターフェイスと、必要に応じて状態オブジェクトを指定します。
どちらの場合も、作業キュー スレッドは IMFAsyncCallback::Invoke メソッドを呼び出します。 Invoke メソッドを使用して作業項目を実行します。
複数のスレッドまたはコンポーネントが同じ作業キューを共有している場合は、 MFLockWorkQueue を呼び出して作業キューをロックできます。これにより、プラットフォームが作業キューを解放できなくなります。 MFAllocateWorkQueue または MFLockWorkQueue の呼び出しごとに、MFUnlockWorkQueue を 1 回呼び出して作業キューを解放する必要があります。 たとえば、新しい作業キューを作成してから 1 回ロックする場合は、 MFUnlockWorkQueue を 2 回呼び出し、 MFAllocateWorkQueue の呼び出しに対して 1 回、 MFLockWorkQueue を呼び出すために 1 回呼び出す必要があります。
次のコードは、新しい作業キューを作成し、作業項目をキューに配置し、作業キューを解放する方法を示しています。
Windows 8の作業キューの詳細については、「作業キューとスレッドの機能強化」を参照してください。
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);
}
この例では、 pCallback がアプリケーションの IMFAsyncCallback インターフェイスへのポインターであることを前提としています。 また、コールバックによって hEvent イベント ハンドルが設定されることを前提としています。 コードは、 MFUnlockWorkQueue を呼び出す前に、このイベントが設定されるのを待機します。
作業キュー スレッドは、呼び出し元のプロセスで常に作成されます。 各作業キュー内で、コールバックがシリアル化されます。 同じ作業キューで MFPutWorkItem を 2 回呼び出した場合、最初のコールバックが返されるまで、2 番目のコールバックは呼び出されません。
作業キューのシャットダウン
MFShutdown を呼び出す前に、作業キュー スレッドで使用されているリソースをすべて解放します。 このプロセスを同期するには、Media Foundation プラットフォームをロックします。これにより、 MFShutdown 関数が作業キュー スレッドを閉じなくなります。 プラットフォームのロック中 に MFShutdown が呼び出された場合、 MFShutdown はプラットフォームのロックが解除されるまで数百ミリ秒待機します。 その時間内にロックが解除されていない場合、 MFShutdown は作業キュー・スレッドをクローズします。
IMFAsyncResult の既定の実装では、結果オブジェクトの作成時に Media Foundation プラットフォームが自動的にロックされます。 インターフェイスを解放すると、プラットフォームのロックが解除されます。 そのため、プラットフォームを直接ロックする必要はほとんどありません。 ただし、 IMFAsyncResult の独自のカスタム実装を記述する場合は、プラットフォームを手動でロックしてロック解除する必要があります。 プラットフォームをロックするには、 MFLockPlatform を呼び出します。 プラットフォームのロックを解除するには、 MFUnlockPlatform を呼び出します。 例については、「 カスタム非同期結果オブジェクト」を参照してください。
MFShutdown を呼び出した後、5 秒のタイムアウト期間内にプラットフォームのロックが解除されていることを確認する必要があります。 これを行うには、すべての IMFAsyncResult ポインターを解放し、プラットフォームを手動でロックした場合は MFUnlockPlatform を呼び出します。 作業キュー スレッドで使用されているリソースを解放するか、アプリケーションがメモリリークを発生させる可能性があることを確認します。
通常、 アプリケーションが MFShutdown を呼び出す前にすべての Media Foundation オブジェクトをシャットダウンして解放する場合、ロックについて心配する必要はありません。 ロック メカニズムを使用すると、 MFShutdown を呼び出した後に、作業キュー スレッドを正常に終了できます。
スケジュールされた作業項目の使用
MFScheduleWorkItem または MFScheduleWorkItemEx を呼び出すことで、一定時間後にコールバックを実行するようにスケジュールできます。
- MFScheduleWorkItem は、コールバック、オプションの状態オブジェクト、タイムアウト間隔へのポインターを受け取ります。
- MFScheduleWorkItemEx は、非同期の結果オブジェクトとタイムアウト値へのポインターを受け取ります。
タイムアウトを負の値としてミリ秒単位で指定します。 たとえば、コールバックが 5 秒で呼び出されるようにスケジュールするには、値 -5000 を使用します。 どちらの関数も MFWORKITEM_KEY 値を返します。この値を使用すると、 コールバックを MFCancelWorkItem 関数に渡すことでコールバックを取り消すことができます。
スケジュールされた作業項目では、常にMFASYNC_CALLBACK_QUEUE_TIMERプラットフォーム作業キューが使用されます。
定期的なコールバックの使用
MFAddPeriodicCallback 関数は、コールバックをキャンセルするまで定期的に呼び出されるようにスケジュールします。 コールバック間隔は固定されています。アプリケーションでは変更できません。 正確な間隔を調べるには、 MFGetTimerPeriodicity を呼び出します。 間隔は 10 ミリ秒の順序であるため、この関数は、プレゼンテーション クロックの実装など、頻繁な "ティック" が必要な状況を対象とします。 操作の頻度を低くするスケジュールを設定する場合は、前に説明したように、スケジュールされた作業項目を使用します。
このトピックで説明する他のコールバックとは異なり、定期的なコールバックでは IMFAsyncCallback インターフェイスは使用されません。 代わりに、関数ポインターを使用します。 詳細については、「 MFPERIODICCALLBACK コールバック」を参照してください。
定期的なコールバックをキャンセルするには、 MFRemovePeriodicCallback を呼び出します。
定期的なコールバックでは、MFASYNC_CALLBACK_QUEUE_TIMER プラットフォームの作業キューが使用されます。
関連トピック