//+--------------------------------------------------------------------------- // // 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 CWorkQueue::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 CWorkQueue::~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 void CWorkQueue::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 void CWorkQueue::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 BOOL CWorkQueue::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