1 //////////////////////////////////////////////////////////////////////////
4 // Async operation queue.
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
7 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
11 // Copyright (c) Microsoft Corporation. All rights reserved.
13 //////////////////////////////////////////////////////////////////////////
17 #pragma warning( push )
18 #pragma warning( disable : 4355 ) // 'this' used in base member initializer list
21 This header file defines an object to help queue and serialize
22 asynchronous operations.
26 To perform an operation asynchronously in Media Foundation, an object
27 does one of the following:
29 1. Calls MFPutWorkItem(Ex), using either a standard work queue
30 identifier or a caller-allocated work queue. The work-queue
31 thread invokes the object's callback.
33 2. Creates an async result object (IMFAsyncResult) and calls
34 MFInvokeCallback to invoke the object's callback.
36 Ultimately, either of these cause the object's callback to be invoked
37 from a work-queue thread. The object can then complete the operation
40 However, the Media Foundation platform may dispatch async callbacks in
41 parallel on several threads. Putting an item on a work queue does NOT
42 guarantee that one operation will complete before the next one starts,
43 or even that work items will be dispatched in the same order they were
46 To serialize async operations that should not overlap, an object should
47 use a queue. While one operation is pending, subsequent operations are
48 put on the queue, and only dispatched after the previous operation is
51 The granularity of a single "operation" depends on the requirements of
52 that particular object. A single operation might involve several
53 asynchronous calls before the object dispatches the next operation on
61 //-------------------------------------------------------------------
62 // OpQueue class template
64 // Base class for an async operation queue.
66 // TOperation: The class used to describe operations. This class must
67 // implement IUnknown.
69 // The OpQueue class is an abstract class. The derived class must
70 // implement the following pure-virtual methods:
72 // - IUnknown methods (AddRef, Release, QI)
74 // - DispatchOperation:
76 // Performs the asynchronous operation specified by pOp.
78 // At the end of each operation, the derived class must call
79 // ProcessQueue to process the next operation in the queue.
81 // NOTE: An operation is not required to complete inside the
82 // DispatchOperation method. A single operation might consist
83 // of several asynchronous method calls.
85 // - ValidateOperation:
87 // Checks whether the object can perform the operation specified
88 // by pOp at this time.
90 // If the object cannot perform the operation now (e.g., because
91 // another operation is still in progress) the method should
92 // return MF_E_NOTACCEPTING.
94 //-------------------------------------------------------------------
98 template <class T, class TOperation>
99 class OpQueue //: public IUnknown
103 typedef ComPtrList<TOperation> OpList;
105 HRESULT QueueOperation(TOperation *pOp);
109 HRESULT ProcessQueue();
110 HRESULT ProcessQueueAsync(IMFAsyncResult *pResult);
112 virtual HRESULT DispatchOperation(TOperation *pOp) = 0;
113 virtual HRESULT ValidateOperation(TOperation *pOp) = 0;
115 OpQueue(CRITICAL_SECTION& critsec)
116 : m_OnProcessQueue(static_cast<T *>(this), &OpQueue::ProcessQueueAsync),
126 OpList m_OpQueue; // Queue of operations.
127 CRITICAL_SECTION& m_critsec; // Protects the queue state.
128 AsyncCallback<T> m_OnProcessQueue; // ProcessQueueAsync callback.
133 //-------------------------------------------------------------------
134 // Place an operation on the queue.
136 //-------------------------------------------------------------------
138 template <class T, class TOperation>
139 HRESULT OpQueue<T, TOperation>::QueueOperation(TOperation *pOp)
143 EnterCriticalSection(&m_critsec);
145 hr = m_OpQueue.InsertBack(pOp);
151 LeaveCriticalSection(&m_critsec);
156 //-------------------------------------------------------------------
157 // Process the next operation on the queue.
160 // Note: This method dispatches the operation to a work queue.
161 //-------------------------------------------------------------------
163 template <class T, class TOperation>
164 HRESULT OpQueue<T, TOperation>::ProcessQueue()
167 if (m_OpQueue.GetCount() > 0)
170 MFASYNC_CALLBACK_QUEUE_STANDARD, // Use the standard work queue.
171 0, // Default priority
172 &m_OnProcessQueue, // Callback method.
173 nullptr // State object.
180 //-------------------------------------------------------------------
181 // Process the next operation on the queue.
184 // Note: This method is called from a work-queue thread.
185 //-------------------------------------------------------------------
187 template <class T, class TOperation>
188 HRESULT OpQueue<T, TOperation>::ProcessQueueAsync(IMFAsyncResult *pResult)
191 TOperation *pOp = nullptr;
193 EnterCriticalSection(&m_critsec);
195 if (m_OpQueue.GetCount() > 0)
197 hr = m_OpQueue.GetFront(&pOp);
201 hr = ValidateOperation(pOp);
205 hr = m_OpQueue.RemoveFront(nullptr);
209 (void)DispatchOperation(pOp);
218 LeaveCriticalSection(&m_critsec);
222 #pragma warning( pop )