一直觉得自己的写的一个对临近区调用的一个封装类很无敌,简简单单就搞定了一个对象内部的线程同步,如果
有全局变量的话,搞定多个对象的线程同步也不是很难,现在看了下ATL的源码,原来和人家毕竟低等的
封装一模一样,惭愧啊。
先看看人家对Section的封装吧,
class CComCriticalSection
{
public:
CComCriticalSection() throw()
{
memset(&m_sec, 0, sizeof(CRITICAL_SECTION));
}
~CComCriticalSection()
{
}
HRESULT Lock() throw()
{
EnterCriticalSection(&m_sec);
return S_OK;
}
HRESULT Unlock() throw()
{
LeaveCriticalSection(&m_sec);
return S_OK;
}
HRESULT Init() throw()
{
HRESULT hRes = E_FAIL;
__try
{
InitializeCriticalSection(&m_sec);
hRes = S_OK;
}
// structured exception may be raised in low memory situations
__except(STATUS_NO_MEMORY == GetExceptionCode())
{
hRes = E_OUTOFMEMORY;
}
return hRes;
}
HRESULT Term() throw()
{
DeleteCriticalSection(&m_sec);
return S_OK;
}
CRITICAL_SECTION m_sec;
};
这个就是简单的对Section封装了一下子,把里面的操作换了个更阳春的名字罢了,没有什么大不了的。
class CComAutoCriticalSection : public CComCriticalSection
{
public:
CComAutoCriticalSection()
{
HRESULT hr = CComCriticalSection::Init();
if (FAILED(hr))
AtlThrow(hr);
}
~CComAutoCriticalSection() throw()
{
CComCriticalSection::Term();
}
private :
HRESULT Init(); // Not implemented. CComAutoCriticalSection::Init should never be called
HRESULT Term(); // Not implemented. CComAutoCriticalSection::Term should never be called
};
这个就是在上面的基础上加了在构造函数初始化和在析构函数中反初始化的操作(自己编的词)
class CComSafeDeleteCriticalSection : public CComCriticalSection
{
public:
CComSafeDeleteCriticalSection(): m_bInitialized(false)
{
}
~CComSafeDeleteCriticalSection() throw()
{
if (!m_bInitialized)
{
return;
}
m_bInitialized = false;
CComCriticalSection::Term();
}
HRESULT Init() throw()
{
ATLASSERT( !m_bInitialized );
HRESULT hr = CComCriticalSection::Init();
if (SUCCEEDED(hr))
{
m_bInitialized = true;
}
return hr;
}
HRESULT Term() throw()
{
if (!m_bInitialized)
{
return S_OK;
}
m_bInitialized = false;
return CComCriticalSection::Term();
}
HRESULT Lock()
{
// CComSafeDeleteCriticalSection::Init or CComAutoDeleteCriticalSection::Init
// not called or failed.
// m_critsec member of CComObjectRootEx is now of type
// CComAutoDeleteCriticalSection. It has to be initialized
// by calling CComObjectRootEx::_AtlInitialConstruct
ATLASSUME(m_bInitialized);
return CComCriticalSection::Lock();
}
private:
bool m_bInitialized;
};
加了个安全保障而已嘛,这些看起来还蛮平凡的。我除了没有它写的精细外,大体还是一样的。
如果单有这个基本可以算是个简单的封装了,在同步开始调用lock,在结束的时候调用unlock 就可以了,但如果有异常的时候
就不行了,如果有异常发生,那么unlock很可能没有调用,这个对于线程同步是致命的。不过不要紧,这个我都搞得定,
使用一个类包一层,在构造的时候加锁,在析构的时候解锁就ok了,ATL也是这么想的。
template< class TLock >
class CComCritSecLock
{
public:
CComCritSecLock( TLock& cs, bool bInitialLock = true );
~CComCritSecLock() throw();
HRESULT Lock() throw();
void Unlock() throw();
// Implementation
private:
TLock& m_cs;
bool m_bLocked;
// Private to avoid accidental use
CComCritSecLock( const CComCritSecLock& ) throw();
CComCritSecLock& operator=( const CComCritSecLock& ) throw();
};
template< class TLock >
inline CComCritSecLock< TLock >::CComCritSecLock( TLock& cs, bool bInitialLock ) :
m_cs( cs ),
m_bLocked( false )
{
if( bInitialLock )
{
HRESULT hr;
hr = Lock();
if( FAILED( hr ) )
{
AtlThrow( hr );
}
}
}
template< class TLock >
inline CComCritSecLock< TLock >::~CComCritSecLock() throw()
{
if( m_bLocked )
{
Unlock();
}
}
template< class TLock >
inline HRESULT CComCritSecLock< TLock >::Lock() throw()
{
HRESULT hr;
ATLASSERT( !m_bLocked );
hr = m_cs.Lock();
if( FAILED( hr ) )
{
return( hr );
}
m_bLocked = true;
return( S_OK );
}
template< class TLock >
inline void CComCritSecLock< TLock >::Unlock() throw()
{
ATLASSUME( m_bLocked );
m_cs.Unlock();
m_bLocked = false;
}
很明显的,这个就是和我想的一模一样的,就是加了个什么模板,可以选择上面的Section封装,这些基本是为了
线程模型用,可以选择安全的,也可以为了效率不安全一点,同时有的时候只有一个线程在玩,没有必要加什么
锁嘛,就有个什么fake 的section类,来玩个假的花样,就是调了跟没调一样。
CComSingleThreadModel就是这样一个东西,它就是定义了一个这种叫做CComFakeCriticalSection的东西来玩同步
基本就是没有同步,而CComMutiThreadModel就是老老实实的同步,它就用了CriticalSection.
也就是说,继承了这两种模型类的一种,也就决定了section的封装类,反正他们最后都被定义成了AutoCriticalSection
的东西。
最后奇怪的是,这个什么seclock它最后没有用,在CComObjectRootEx中,选择的一个_AutoDelCritSec的成员Section
它是ThreadModel的AutoDeleteCriticalSection,就是那个不能调用Term的家伙,在它里面还有一个真正的sectionlock ,这个lock
和CComObjectRootEx使用一样的线程模型模板,同时它在构造的时候加锁,在析构的时候解锁,用的就是这个成员section
在使用的时候,对象由于继承了CComObjectRootEx那么它就直接有了这个几个成员变量,那么在它用同步的函数中,直接定义一个
objectlock,然后将自己的指针作为参数传入就可以了,这样相当于把成员锁传入了,这样CComObjectLockT就可以实现我刚才说
的功能了,过程是复杂了点,但功能有点像.net中的使用,在对象自身中放个同步的锁,在成员函数要同步的时候,使用
IsSynchronze(this)就可以了,和这里的使用有点类似。
下面就是这个简单的CComObjectLockT,和刚才的那个简直就是一样的。
template <class ThreadModel>
class CComObjectLockT
{
public:
CComObjectLockT(CComObjectRootEx<ThreadModel>* p)
{
if (p)
p->Lock();
m_p = p;
}
~CComObjectLockT()
{
if (m_p)
m_p->Unlock();
}
CComObjectRootEx<ThreadModel>* m_p;
};