|
|
//
// MODULE: SYNC.CPP
//
// PURPOSE: syncronization classes
//
// COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
//
// AUTHOR: Oleg Kalosha
//
// ORIGINAL DATE: 8-04-98
//
// NOTES:
//
// Version Date By Comments
//--------------------------------------------------------------------
// V3.0 08-04-98 OK
//
#include "stdafx.h"
#include <algorithm>
#include "sync.h"
#include "event.h"
#include "baseexception.h"
#include "CharConv.h"
#include "apiwraps.h"
////////////////////////////////////////////////////////////////////////////////////
// CSyncObj
// single sync object abstract class
////////////////////////////////////////////////////////////////////////////////////
CSyncObj::CSyncObj() { // we are to initialize handle in specific inherited class
}
CSyncObj::~CSyncObj() { ::CloseHandle(m_handle); }
HANDLE CSyncObj::GetHandle() const { return m_handle; }
////////////////////////////////////////////////////////////////////////////////////
// CMutexObj //
// single mutex object class
// Manages a single mutex handle to facilitate waiting for the mutex.
////////////////////////////////////////////////////////////////////////////////////
CMutexObj::CMutexObj() : CSyncObj() { m_handle = ::CreateMutex(NULL, FALSE, NULL); }
CMutexObj::~CMutexObj() { ::CloseHandle(m_handle); }
// Smarter strategy here than an infinite wait. Wait up to 60 seconds, then log to event
// log and wait infinitely. If it's logged to event log & eventually gets the mutex,
// it logs to say it finally got the mutex.
void CMutexObj::Lock() { WAIT_INFINITE(m_handle); }
void CMutexObj::Unlock() { ::ReleaseMutex(m_handle); }
////////////////////////////////////////////////////////////////////////////////////
// CMultiSyncObj //
// multiple sync object abstract class
// Manages multiple handles (the exact type of handle will be determined by a class
// inheriting from this) to facilitate waiting for the union of several events.
////////////////////////////////////////////////////////////////////////////////////
CMultiSyncObj::CMultiSyncObj() { }
CMultiSyncObj::~CMultiSyncObj() { }
void CMultiSyncObj::AddHandle(HANDLE handle) { vector<HANDLE>::iterator i = find(m_arrHandle.begin(), m_arrHandle.end(), handle); if (i == m_arrHandle.end()) { try { m_arrHandle.push_back(handle); } catch (exception& x) { CString str; // Note STL exception in event log.
CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ ); CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(), SrcLoc.GetSrcFileLineStr(), CCharConversion::ConvertACharToString(x.what(), str), _T(""), EV_GTS_STL_EXCEPTION ); } } }
void CMultiSyncObj::RemoveHandle(HANDLE handle) { vector<HANDLE>::iterator i = find(m_arrHandle.begin(), m_arrHandle.end(), handle); if (i != m_arrHandle.end()) m_arrHandle.erase(i); }
void CMultiSyncObj::Clear() { m_arrHandle.clear(); }
////////////////////////////////////////////////////////////////////////////////////
// CMultiMutexObj //
// Manages multiple mutex handles to facilitate waiting for the union of several mutexes.
////////////////////////////////////////////////////////////////////////////////////
CMultiMutexObj::CMultiMutexObj() : CMultiSyncObj() { }
CMultiMutexObj::~CMultiMutexObj() { }
// Deprecated use, because it provides inferior logging.
void CMultiMutexObj::Lock() { Lock(__FILE__, __LINE__); }
void CMultiMutexObj::Lock( LPCSTR srcFile, // Calling source file (__FILE__), used for logging.
// LPCSTR, not LPCTSTR, because __FILE__ is a char*, not a TCHAR*
int srcLine, // Calling source line (__LINE__), used for logging.
DWORD TimeOutVal /*=60000*/ // Time-out interval in milliseconds. After
// this we log an error, then wait infinitely
) { CBuildSrcFileLinenoStr SrcLoc( srcFile, srcLine ); DWORD nWaitRetVal= ::WaitForMultipleObjects( m_arrHandle.size(), m_arrHandle.begin(), TRUE, // wait for all objects, not just one.
TimeOutVal);
if (nWaitRetVal == WAIT_FAILED) { // very bad news, should never happen
DWORD dwErr = ::GetLastError(); CString strErr; strErr.Format(_T("%d"), dwErr); CBuildSrcFileLinenoStr SrcLoc3(__FILE__, __LINE__); CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(), SrcLoc3.GetSrcFileLineStr(), _T("Thread wait failed."), strErr, EV_GTS_ERROR_STUCK_THREAD ); } else if (nWaitRetVal == WAIT_TIMEOUT) { // Initial wait timed out, note in log, and wait infinitely.
CBuildSrcFileLinenoStr SrcLoc1(__FILE__, __LINE__); CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(), SrcLoc1.GetSrcFileLineStr(), _T("Thread wait exceeded initial timeout interval."), _T(""), EV_GTS_STUCK_THREAD );
nWaitRetVal= ::WaitForMultipleObjects( m_arrHandle.size(), m_arrHandle.begin(), TRUE, // wait for all objects, not just one.
INFINITE);
// If successfully got what we were waiting for (after logging an apparent
// problem), log the fact that it's ultimately OK.
if (nWaitRetVal == WAIT_OBJECT_0) { CBuildSrcFileLinenoStr SrcLoc2(__FILE__, __LINE__); CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(), SrcLoc2.GetSrcFileLineStr(), _T("Thread infinite wait succeeded."), _T(""), EV_GTS_STUCK_THREAD ); } }
// Else we don't really care what else ::WaitForMultipleObjects() returns.
// If we get here we got what we were waiting for
}
void CMultiMutexObj::Unlock() { for (vector<HANDLE>::iterator i = m_arrHandle.begin(); i != m_arrHandle.end(); i++ ) ::ReleaseMutex(*i); }
|