// // MODULE: Stateless.CPP // // PURPOSE: CStateless is the base for a hierarchy of classes intended for stateless operation // in a multithreaded environment. The idea is that each public method in any class inheriting // from CStateless should be atomic. Typically, a public method will begin with Lock() and // end with Unlock(). It should represent a complete process. // In general, public methods should fall into two categories. // 1. Determine certain irreversible statuses (e.g. whether certain things are initialized). // 2. Perform atomic operations. For example, it is appropriate to write a method that // will take a complete set of node states and return a vector of recommendations. // // It is NOT appropriate to write methods to // - associate a a single node and state, this method to be called repeatedly // - get a vector of recommendations based on previousl established node/state associations. // This relies on a state to be maintained across calls, but that state may be lost due to // other threads using the same object. // // It is legitimate, but not recommended to write the following methods: // - associate a uniquely identified query, a node, and a state // - get a vector of recommendations for a uniquely identified query, based on node/state // associations. // This last approach is not truly stateless, but at least provides sufficient information to // allow appropriate preservation of state without denying other threads the use of the // CStateless object. // // // COMPANY: Saltmine Creative, Inc. (206)-284-7511 support@saltmine.com // // AUTHOR: Joe Mabel // // ORIGINAL DATE: 9-9-98 // // NOTES: // 1. Lock() and Unlock() are const methods so that (for example) a simple "get" in a // class which inherits from this can be const. E.g.: // // class CFoo : public CStateless // { // int i; // public: // int GetI() const // { // Lock(); // int ret = i; // Unlock(); // retrn ret; // } // ... // }; // // Version Date By Comments //-------------------------------------------------------------------- // V3.0 9-9-98 JM // #include "stdafx.h" #include "Stateless.h" #include "APIWraps.h" #include "Event.h" #include "BaseException.h" #include using namespace std; //////////////////////////////////////////////////////////////////////////////////// // CStateless ///////////////////////////////////////////////////////////////////////////////////// CStateless::CStateless(DWORD TimeOutVal /*= 60000 */) { m_TimeOutVal = TimeOutVal; m_hMutex = ::CreateMutex(NULL, FALSE, NULL); if (!m_hMutex) { CBuildSrcFileLinenoStr SrcLoc( __FILE__, __LINE__ ); CEvent::ReportWFEvent( SrcLoc.GetSrcFileLineStr(), SrcLoc.GetSrcFileLineStr(), _T("Hourly"), _T(""), EV_GTS_ERROR_MUTEX ); throw bad_alloc(); } } CStateless::~CStateless() { ::CloseHandle(m_hMutex); } void CStateless::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. ) const { APIwraps::WaitAndLogIfSlow(m_hMutex, srcFile, srcLine, m_TimeOutVal); } void CStateless::Unlock() const { ::ReleaseMutex(m_hMutex); } // this function is needed to support multi-mutex locking. HANDLE CStateless::GetMutexHandle() const { return m_hMutex; } //////////////////////////////////////////////////////////////////////////////////// // CNameStateless ///////////////////////////////////////////////////////////////////////////////////// CNameStateless::CNameStateless() : CStateless() { } CNameStateless::CNameStateless(const CString& str) : CStateless() { LOCKOBJECT(); m_strName = str; UNLOCKOBJECT(); } void CNameStateless::Set(const CString& str) { LOCKOBJECT(); m_strName = str; UNLOCKOBJECT(); } CString CNameStateless::Get() const { LOCKOBJECT(); CString ret = _T(""); if ( true != m_strName.IsEmpty() ) ret = m_strName; UNLOCKOBJECT(); return ret; }