You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
8.3 KiB
273 lines
8.3 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1996.
|
|
//
|
|
// File: workq.cxx
|
|
//
|
|
// Contents: Definitions of CWorkQueue methods
|
|
//
|
|
// Classes:
|
|
//
|
|
// Functions: Constructor, destructor, AddItem, GetNextItem, Done
|
|
//
|
|
// Coupling:
|
|
//
|
|
// Notes: For use in uni- or multi-threaded applications
|
|
//
|
|
// History: 9-30-1996 ericne Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "workq.hxx"
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: ::CWorkQueue
|
|
//
|
|
// Synopsis: Initializes members
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 9-30-1996 ericne Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template<class T, int I>
|
|
CWorkQueue<T,I>::CWorkQueue()
|
|
: m_iAddItemIndex( 0 ),
|
|
m_iGetItemIndex( 0 ),
|
|
m_hSemFull( NULL ),
|
|
m_hSemEmpty( NULL ),
|
|
m_hEventDone( NULL )
|
|
|
|
{
|
|
InitializeCriticalSection( &m_CriticalSection );
|
|
|
|
// Create a semaphore with an initial count of 0. Each time
|
|
// GetItem is called, this value is decrimented. Each time
|
|
// AddItem is called, this value is incremented.
|
|
while( 1 )
|
|
{
|
|
m_hSemFull = CreateSemaphore( NULL, // No security attributes
|
|
0, // Initial value of 0
|
|
I, // Maximum value of I
|
|
NULL ); // No name
|
|
if( NULL != m_hSemFull )
|
|
break;
|
|
printf( "CreateSemaphore failed. Will try again in %d milliseconds.\r\n"
|
|
"GetLastError() returned 0x%08x\r\n",
|
|
dwSleepTime, GetLastError() );
|
|
Sleep( dwSleepTime );
|
|
}
|
|
|
|
// Create a semaphore with an initial count of I. Each time
|
|
// AddItem is called, this value is decrimented. Each time
|
|
// GetItem is called, this value is incremented.
|
|
while( 1 )
|
|
{
|
|
m_hSemEmpty = CreateSemaphore( NULL, // No security attributes
|
|
I, // Initial value of I
|
|
I, // Maximum value of I
|
|
NULL ); // No name
|
|
if( NULL != m_hSemEmpty )
|
|
break;
|
|
printf( "CreateSemaphore failed. Will try again in %d milliseconds.\r\n"
|
|
"GetLastError() returned 0x%08x\r\n",
|
|
dwSleepTime, GetLastError() );
|
|
Sleep( dwSleepTime );
|
|
}
|
|
|
|
// This event is used by a producer thread to signal the consumer threads
|
|
// that no additional work items will be placed in the queue
|
|
while( 1 )
|
|
{
|
|
m_hEventDone = CreateEvent( NULL, // No security attributes
|
|
TRUE, // Manual reset
|
|
FALSE, // Initial state of non-signaled
|
|
NULL ); // No name
|
|
if( NULL != m_hEventDone )
|
|
break;
|
|
printf( "CreateEvent failed. Will try again in %d milliseconds.\r\n"
|
|
"GetLastError() returned 0x%08x\r\n",
|
|
dwSleepTime, GetLastError() );
|
|
Sleep( dwSleepTime );
|
|
}
|
|
|
|
} //::CWorkQueue
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: ::~CWorkQueue
|
|
//
|
|
// Synopsis: Closes the handles to the semaphores
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns:
|
|
//
|
|
// History: 9-30-1996 ericne Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template<class T, int I>
|
|
CWorkQueue<T,I>::~CWorkQueue()
|
|
{
|
|
|
|
if( ! CloseHandle( m_hSemFull ) )
|
|
printf( "~CWorkQueue(): Could not close handle to semaphore."
|
|
"GetLastError() returns 0x%08x", GetLastError() );
|
|
|
|
if( ! CloseHandle( m_hSemEmpty ) )
|
|
printf( "~CWorkQueue(): Could not close handle to semaphore."
|
|
"GetLastError() returns 0x%08x", GetLastError() );
|
|
|
|
if( ! CloseHandle( m_hEventDone ) )
|
|
printf( "~CWorkQueue(): Could not close handle to event."
|
|
"GetLastError() returns 0x%08x", GetLastError() );
|
|
|
|
DeleteCriticalSection( &m_CriticalSection );
|
|
|
|
} //::~CWorkQueue
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: ::AddItem
|
|
//
|
|
// Synopsis: Adds an item to the queue
|
|
//
|
|
// Arguments: [ToAdd] -- The item to add
|
|
//
|
|
// Returns: none
|
|
//
|
|
// History: 9-30-1996 ericne Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template<class T, int I>
|
|
void CWorkQueue<T,I>::AddItem( const T &ToAdd )
|
|
{
|
|
|
|
// Wait until m_hSemEmpty is greater than zero, then decriment
|
|
if( WAIT_OBJECT_0 != WaitForSingleObject( m_hSemEmpty, INFINITE ) )
|
|
printf( "CWorkQueue::AddItem() : Wait for semaphore failed.\r\n"
|
|
"GetLastError() returns 0x%08x\r\n", GetLastError() );
|
|
|
|
// enter the critical section
|
|
EnterCriticalSection( &m_CriticalSection );
|
|
|
|
// Bit-wise copy the structure
|
|
memcpy( (void*)&m_WorkItems[m_iAddItemIndex], (void*)&ToAdd, sizeof( T ) );
|
|
|
|
// Increment the index
|
|
m_iAddItemIndex = ( m_iAddItemIndex + 1 ) % I;
|
|
|
|
// Leave the critical section
|
|
LeaveCriticalSection( &m_CriticalSection );
|
|
|
|
// Incriment m_hSemFull
|
|
if( ! ReleaseSemaphore( m_hSemFull, 1, NULL ) )
|
|
printf( "CWorkQueue::AddItem() : Could not release semaphore.\r\n"
|
|
"GetLastError() returns 0x%08x\r\n", GetLastError() );
|
|
|
|
} //::AddItem
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: ::Done
|
|
//
|
|
// Synopsis: Called by a producer thread when it is finished adding stuff
|
|
// to the queue
|
|
//
|
|
// Arguments: (none)
|
|
//
|
|
// Returns: void
|
|
//
|
|
// History: 10-01-1996 ericne Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template<class T, int I>
|
|
void CWorkQueue<T,I>::Done( )
|
|
{
|
|
|
|
// Since this is a manual-reset event, m_hEventDone stays signaled forever.
|
|
SetEvent( m_hEventDone );
|
|
|
|
} //::Done
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: ::GetItem
|
|
//
|
|
// Synopsis: Gets the next work item from the queue.
|
|
//
|
|
// Arguments: [NextItem] -- Passed by reference. Item is filled in by
|
|
// the function
|
|
//
|
|
// Returns: TRUE if an item was gotten from the queue
|
|
// FALSE if queue is empty and m_hEventDone is signaled
|
|
//
|
|
// History: 9-30-1996 ericne Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template<class T, int I>
|
|
BOOL CWorkQueue<T,I>::GetItem( T &NextItem )
|
|
{
|
|
|
|
DWORD dwWait = 0;
|
|
HANDLE pHandles[2] = { m_hSemFull, m_hEventDone };
|
|
|
|
// wait until m_hSemFull is > 0 or until m_hEventDone is set
|
|
dwWait = WaitForMultipleObjects( 2, pHandles, FALSE, INFINITE );
|
|
|
|
if( WAIT_OBJECT_0 == dwWait )
|
|
{
|
|
// There are more work items in the list
|
|
// ( done event may or may not be set )
|
|
|
|
EnterCriticalSection( &m_CriticalSection );
|
|
|
|
memcpy( (void*) &NextItem,
|
|
(void*) &m_WorkItems[m_iGetItemIndex],
|
|
sizeof( T ) );
|
|
|
|
m_iGetItemIndex = ( m_iGetItemIndex + 1 ) % I;
|
|
|
|
LeaveCriticalSection( &m_CriticalSection );
|
|
|
|
if( ! ReleaseSemaphore( m_hSemEmpty, 1, NULL ) )
|
|
printf( "CWorkQueue::GetItem() : Could not release semaphore.\r\n"
|
|
"GetLastError() returns 0x%08x\r\n", GetLastError() );
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
else if( WAIT_OBJECT_0 + 1 == dwWait )
|
|
{
|
|
// Nothing more in list and done event has been set
|
|
}
|
|
else
|
|
{
|
|
// An error occured
|
|
printf( "CWorkQueue::GetItem() : Wait failed.\r\n"
|
|
"GetLastError() returns 0x%08x\r\n", GetLastError() );
|
|
}
|
|
|
|
return( FALSE );
|
|
|
|
} //::GetItem
|
|
|