// called on thread to process any active requests void CAsyncIo::ProcessRequests(void) { // lock to get the item and increment the outstanding count CAsyncRequest * preq = NULL; for(;;) { { CAutoLock lock(&m_csLists); preq = GetWorkItem(); if(preq == NULL) { // done return; } // one more item not on the done or work list m_cItemsOut++; // release critsec } preq->Complete(); // regain critsec to replace on done list { CAutoLock l(&m_csLists); PutDoneItem(preq); if(--m_cItemsOut == 0) { if(m_bWaiting) m_evAllDone.Set(); } } } }
void CAsyncIo::ProcessRequests(void) { CAsyncRequest * preq = NULL; for (;;) { { CAutoLock lock(&m_csLists); preq = GetWorkItem(); if (preq == NULL) { return; } m_cItemsOut++; } preq->Complete(); { CAutoLock l(&m_csLists); PutDoneItem(preq); if (--m_cItemsOut == 0) { if (m_bWaiting) { m_evAllDone.Set(); } } } } }
HRESULT CAsyncIo::BeginFlush() { { CAutoLock lock(&m_csLists); m_bFlushing = TRUE; CAsyncRequest * preq; while(preq = GetWorkItem()) { preq->Cancel(); PutDoneItem(preq); } if (m_cItemsOut > 0) { ASSERT(!m_bWaiting); m_bWaiting = TRUE; } else { m_evDone.Set(); return S_OK; } } ASSERT(m_bWaiting); for (;;) { m_evAllDone.Wait(); { CAutoLock lock(&m_csLists); if (m_cItemsOut == 0) { m_bWaiting = FALSE; m_evDone.Set(); return S_OK; } } } }
// cancel all items on the worklist onto the done list // and refuse further requests or further WaitForNext calls // until the end flush // // WaitForNext must return with NULL only if there are no successful requests. // So Flush does the following: // 1. set m_bFlushing ensures no more requests succeed // 2. move all items from work list to the done list. // 3. If there are any outstanding requests, then we need to release the // critsec to allow them to complete. The m_bWaiting as well as ensuring // that we are signalled when they are all done is also used to indicate // to WaitForNext that it should continue to block. // 4. Once all outstanding requests are complete, we force m_evDone set and // m_bFlushing set and m_bWaiting false. This ensures that WaitForNext will // not block when the done list is empty. HRESULT CAsyncIo::BeginFlush() { // hold the lock while emptying the work list { CAutoLock lock(&m_csLists); // prevent further requests being queued. // Also WaitForNext will refuse to block if this is set // unless m_bWaiting is also set which it will be when we release // the critsec if there are any outstanding). m_bFlushing = TRUE; CAsyncRequest * preq; while((preq = GetWorkItem()) != 0) { preq->Cancel(); PutDoneItem(preq); } // now wait for any outstanding requests to complete if(m_cItemsOut > 0) { // can be only one person waiting ASSERT(!m_bWaiting); // this tells the completion routine that we need to be // signalled via m_evAllDone when all outstanding items are // done. It also tells WaitForNext to continue blocking. m_bWaiting = TRUE; } else { // all done // force m_evDone set so that even if list is empty, // WaitForNext will not block // don't do this until we are sure that all // requests are on the done list. m_evDone.Set(); return S_OK; } } ASSERT(m_bWaiting); // wait without holding critsec for(;;) { m_evAllDone.Wait(); { // hold critsec to check CAutoLock lock(&m_csLists); if(m_cItemsOut == 0) { // now we are sure that all outstanding requests are on // the done list and no more will be accepted m_bWaiting = FALSE; // force m_evDone set so that even if list is empty, // WaitForNext will not block // don't do this until we are sure that all // requests are on the done list. m_evDone.Set(); return S_OK; } } } }