215 lines
5.6 KiB
C++
215 lines
5.6 KiB
C++
|
//
|
||
|
// MODULE: SYNC.CPP
|
||
|
//
|
||
|
// PURPOSE: syncronization classes
|
||
|
//
|
||
|
// COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com
|
||
|
//
|
||
|
// 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);
|
||
|
}
|