| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- //////////////////////////////////////////////////////////////////////////
- //
- // OpQueue.h
- // Async operation queue.
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
- // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
- // PARTICULAR PURPOSE.
- //
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //
- //////////////////////////////////////////////////////////////////////////
- #pragma once
- #pragma warning( push )
- #pragma warning( disable : 4355 ) // 'this' used in base member initializer list
- /*
- This header file defines an object to help queue and serialize
- asynchronous operations.
- Background:
- To perform an operation asynchronously in Media Foundation, an object
- does one of the following:
- 1. Calls MFPutWorkItem(Ex), using either a standard work queue
- identifier or a caller-allocated work queue. The work-queue
- thread invokes the object's callback.
- 2. Creates an async result object (IMFAsyncResult) and calls
- MFInvokeCallback to invoke the object's callback.
- Ultimately, either of these cause the object's callback to be invoked
- from a work-queue thread. The object can then complete the operation
- inside the callback.
- However, the Media Foundation platform may dispatch async callbacks in
- parallel on several threads. Putting an item on a work queue does NOT
- guarantee that one operation will complete before the next one starts,
- or even that work items will be dispatched in the same order they were
- called.
- To serialize async operations that should not overlap, an object should
- use a queue. While one operation is pending, subsequent operations are
- put on the queue, and only dispatched after the previous operation is
- complete.
- The granularity of a single "operation" depends on the requirements of
- that particular object. A single operation might involve several
- asynchronous calls before the object dispatches the next operation on
- the queue.
- */
- //-------------------------------------------------------------------
- // OpQueue class template
- //
- // Base class for an async operation queue.
- //
- // TOperation: The class used to describe operations. This class must
- // implement IUnknown.
- //
- // The OpQueue class is an abstract class. The derived class must
- // implement the following pure-virtual methods:
- //
- // - IUnknown methods (AddRef, Release, QI)
- //
- // - DispatchOperation:
- //
- // Performs the asynchronous operation specified by pOp.
- //
- // At the end of each operation, the derived class must call
- // ProcessQueue to process the next operation in the queue.
- //
- // NOTE: An operation is not required to complete inside the
- // DispatchOperation method. A single operation might consist
- // of several asynchronous method calls.
- //
- // - ValidateOperation:
- //
- // Checks whether the object can perform the operation specified
- // by pOp at this time.
- //
- // If the object cannot perform the operation now (e.g., because
- // another operation is still in progress) the method should
- // return MF_E_NOTACCEPTING.
- //
- //-------------------------------------------------------------------
- #include "linklist.h"
- #include "AsyncCB.h"
- template <class T, class TOperation>
- class OpQueue //: public IUnknown
- {
- public:
- typedef ComPtrList<TOperation> OpList;
- HRESULT QueueOperation(TOperation *pOp);
- protected:
- HRESULT ProcessQueue();
- HRESULT ProcessQueueAsync(IMFAsyncResult *pResult);
- virtual HRESULT DispatchOperation(TOperation *pOp) = 0;
- virtual HRESULT ValidateOperation(TOperation *pOp) = 0;
- OpQueue(CRITICAL_SECTION& critsec)
- : m_OnProcessQueue(static_cast<T *>(this), &OpQueue::ProcessQueueAsync),
- m_critsec(critsec)
- {
- }
- virtual ~OpQueue()
- {
- }
- protected:
- OpList m_OpQueue; // Queue of operations.
- CRITICAL_SECTION& m_critsec; // Protects the queue state.
- AsyncCallback<T> m_OnProcessQueue; // ProcessQueueAsync callback.
- };
- //-------------------------------------------------------------------
- // Place an operation on the queue.
- // Public method.
- //-------------------------------------------------------------------
- template <class T, class TOperation>
- HRESULT OpQueue<T, TOperation>::QueueOperation(TOperation *pOp)
- {
- HRESULT hr = S_OK;
- EnterCriticalSection(&m_critsec);
- hr = m_OpQueue.InsertBack(pOp);
- if (SUCCEEDED(hr))
- {
- hr = ProcessQueue();
- }
- LeaveCriticalSection(&m_critsec);
- return hr;
- }
- //-------------------------------------------------------------------
- // Process the next operation on the queue.
- // Protected method.
- //
- // Note: This method dispatches the operation to a work queue.
- //-------------------------------------------------------------------
- template <class T, class TOperation>
- HRESULT OpQueue<T, TOperation>::ProcessQueue()
- {
- HRESULT hr = S_OK;
- if (m_OpQueue.GetCount() > 0)
- {
- hr = MFPutWorkItem2(
- MFASYNC_CALLBACK_QUEUE_STANDARD, // Use the standard work queue.
- 0, // Default priority
- &m_OnProcessQueue, // Callback method.
- nullptr // State object.
- );
- }
- return hr;
- }
- //-------------------------------------------------------------------
- // Process the next operation on the queue.
- // Protected method.
- //
- // Note: This method is called from a work-queue thread.
- //-------------------------------------------------------------------
- template <class T, class TOperation>
- HRESULT OpQueue<T, TOperation>::ProcessQueueAsync(IMFAsyncResult *pResult)
- {
- HRESULT hr = S_OK;
- TOperation *pOp = nullptr;
- EnterCriticalSection(&m_critsec);
- if (m_OpQueue.GetCount() > 0)
- {
- hr = m_OpQueue.GetFront(&pOp);
- if (SUCCEEDED(hr))
- {
- hr = ValidateOperation(pOp);
- }
- if (SUCCEEDED(hr))
- {
- hr = m_OpQueue.RemoveFront(nullptr);
- }
- if (SUCCEEDED(hr))
- {
- (void)DispatchOperation(pOp);
- }
- }
- if (pOp != nullptr)
- {
- pOp->Release();
- }
- LeaveCriticalSection(&m_critsec);
- return hr;
- }
- #pragma warning( pop )
|