windows-nt/Source/XPSP1/NT/printscan/ui/uicommon/tspqueue.h
2020-09-26 16:20:57 +08:00

297 lines
6.6 KiB
C++

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORPORATION, 1998
*
* TITLE: TSPQUEUE.H
*
* VERSION: 1.0
*
* AUTHOR: ShaunIv
*
* DATE: 5/4/1999
*
* DESCRIPTION: Thread Safe Priority Queue template class
*
*******************************************************************************/
#ifndef __TSPQUEUE_H_INCLUDED
#define __TSPQUEUE_H_INCLUDED
#include "simevent.h"
#include "simcrit.h"
#include "miscutil.h"
template <class T>
class CThreadSafePriorityQueue
{
public:
enum
{
PriorityLow = 1,
PriorityNormal = 2,
PriorityHigh = 3,
PriorityUrgent = 4
};
private:
class CQueueNode
{
private:
T *m_pData;
int m_nPriority;
CQueueNode *m_pNext;
public:
CQueueNode( T *pData, int nPriority=PriorityNormal )
: m_pData(NULL), m_nPriority(nPriority), m_pNext(NULL)
{
m_pData = pData;
}
virtual ~CQueueNode(void)
{
if (m_pData)
{
delete m_pData;
m_pData = NULL;
}
m_pNext = NULL;
}
const CQueueNode *Next(void) const
{
return m_pNext;
}
CQueueNode *Next(void)
{
return m_pNext;
}
CQueueNode *Next( CQueueNode *pNext )
{
return (m_pNext=pNext);
}
T *DetachData()
{
T *pResult = m_pData;
m_pData = NULL;
return pResult;
}
const T *Data(void) const
{
return m_pData;
}
T *Data(void)
{
return m_pData;
}
int Priority(void) const
{
return m_nPriority;
}
int Priority( int nPriority )
{
return (m_nPriority=nPriority);
}
};
private:
CQueueNode *m_pHead;
mutable CSimpleCriticalSection m_CriticalSection;
CSimpleEvent m_QueueEvent;
CSimpleEvent m_PauseEvent;
private:
// No implementation
CThreadSafePriorityQueue( const CThreadSafePriorityQueue & );
CThreadSafePriorityQueue &operator=( const CThreadSafePriorityQueue & );
public:
CThreadSafePriorityQueue(void)
: m_pHead(NULL)
{
m_QueueEvent.Reset();
m_PauseEvent.Signal();
}
~CThreadSafePriorityQueue(void)
{
CAutoCriticalSection cs(m_CriticalSection);
while (m_pHead)
{
CQueueNode *pCurr = m_pHead;
m_pHead = m_pHead->Next();
delete pCurr;
}
}
bool Empty( void ) const
{
CAutoCriticalSection cs(m_CriticalSection);
return (NULL == m_pHead);
}
CQueueNode *Enqueue( T *pData, int nPriority=PriorityNormal )
{
//
// Grab the critical section
//
CAutoCriticalSection cs(m_CriticalSection);
//
// Assume we will not be able to add a new item to the queue
//
CQueueNode *pResult = NULL;
//
// Make sure we have a valid data item
//
if (pData)
{
//
// Try to allocate a new queue node
//
pResult = new CQueueNode(pData,nPriority);
if (pResult)
{
//
// This might be the first item in the queue
//
bool bMaybeSignal = Empty();
//
// If this is an empty queue or we need to do it right away, put it at the head of the queue
//
if (!m_pHead || pResult->Priority() >= PriorityUrgent)
{
pResult->Next(m_pHead);
m_pHead = pResult;
}
else
{
//
// Find the right place to put it
//
CQueueNode *pCurr = m_pHead;
CQueueNode *pPrev = NULL;
while (pCurr && pCurr->Priority() >= pResult->Priority())
{
pPrev = pCurr;
pCurr = pCurr->Next();
}
//
// Insert it in the proper place
//
if (pPrev)
{
pResult->Next(pCurr);
pPrev->Next(pResult);
}
else
{
pResult->Next(m_pHead);
m_pHead = pResult;
}
}
//
// If we were able to allocate the item, and the list isn't empty, signal the queue
//
if (bMaybeSignal && !Empty())
{
//
// Got one!
//
Signal();
//
// Force a yield if this is a high priority message
//
if (pResult->Priority() >= PriorityHigh)
{
Sleep(0);
}
}
}
}
return pResult;
}
T *Dequeue(void)
{
//
// Grab the critical section
//
CAutoCriticalSection cs(m_CriticalSection);
//
// Wait until we are not paused
//
WiaUiUtil::MsgWaitForSingleObject( m_PauseEvent.Event(), INFINITE );
//
// If there are no items, return
//
if (Empty())
{
return NULL;
}
//
// Grab the first item
//
CQueueNode *pFront = m_pHead;
//
// Advance to the next item
//
m_pHead = m_pHead->Next();
//
// Get the data
//
T *pResult = pFront->DetachData();
//
// Delete the queue item
//
delete pFront;
//
// If the queue is now empty, reset the event
//
if (Empty())
{
m_QueueEvent.Reset();
}
//
// Return any data we got
//
return pResult;
}
void Pause(void)
{
m_PauseEvent.Reset();
}
void Resume(void)
{
m_PauseEvent.Signal();
}
void Signal(void)
{
m_QueueEvent.Signal();
}
HANDLE QueueEvent(void)
{
return m_QueueEvent.Event();
}
};
#endif //__TSPQUEUE_H_INCLUDED