如下为CMutex的类定义
class CMutex : public CSyncObject { DECLARE_DYNAMIC(CMutex) // Constructor public: /* explicit */ CMutex(BOOL bInitiallyOwn = FALSE, LPCTSTR lpszName = NULL, LPSECURITY_ATTRIBUTES lpsaAttribute = NULL); // Implementation public: virtual ~CMutex(); BOOL Unlock(); };
构造函数如下
CMutex::CMutex(BOOL bInitiallyOwn, LPCTSTR pstrName, LPSECURITY_ATTRIBUTES lpsaAttribute /* = NULL */) : CSyncObject(pstrName) { m_hObject = ::CreateMutex(lpsaAttribute, bInitiallyOwn, pstrName); if (m_hObject == NULL) AfxThrowResourceException(); }
m_hObject为基类的成员变量,其实也就是Handle了,这里可以创建或者获得一个Mutex的Handle.若m_hObject == NULL(没有获得Mutex的Handle,在已存在Mutex的情况下也是能返回一个已存在的Handle的),抛出异常。具体MSDN CreateMutex.
再看看Lock函数:从基类CSyncObject继承
BOOL CSyncObject::Lock(DWORD dwTimeout) { DWORD dwRet = ::WaitForSingleObject(m_hObject, dwTimeout); if (dwRet == WAIT_OBJECT_0 || dwRet == WAIT_ABANDONED) return TRUE; else return FALSE; }
调用WaitForSingleObject api,dwTimeout默认为INFINITE,根据WaitForSingleObject返回的结果,正常取得访问权限返回OR超时返回,返回TRUE OR FALSE
再看UnLock函数
BOOL CMutex::Unlock() { return ::ReleaseMutex(m_hObject); }
这里是UnLock函数,简单地调用 ReleaseMutex释放拥有的Mutex对象.
那么Handle从哪里释放呢?
CSyncObject::~CSyncObject() { if (m_hObject != NULL) { ::CloseHandle(m_hObject); m_hObject = NULL; } }
基类的析构函数释放了Handle,而Mutex类中的析构函数没有具体实现.
接下来说一个值得注意的地方:
注意从Mutex构造函数的初始化列表中对基类进行初始化传入的pstrName,被赋值给了m_strName,而这是一个只有在Debug版本下才有的成员变量,估计是帮助调试用的——互斥对象名在系统内核中,用一个成员变量作为拷贝可以方便查看互斥对象名,注意Release版本中无此变量.
CSyncObject::CSyncObject(LPCTSTR pstrName) { UNUSED(pstrName); // unused in release builds m_hObject = NULL; #ifdef _DEBUG m_strName = pstrName; #endif }
给一个简单的使用示例..
#include <iostream> #include <afxmt.h> using namespace std; CMutex g_Mutex(FALSE, __T("something different"), NULL); DWORD WINAPI ThreadFunc(LPVOID); int main() { HANDLE l_hChildThread; l_hChildThread = (HANDLE)::CreateThread(NULL, 0, ThreadFunc, NULL, 0, NULL); g_Mutex.Lock(); cout<<"通知子线程开始工作"<<endl; system("pause"); g_Mutex.Unlock();; WaitForSingleObject(l_hChildThread, INFINITE); CloseHandle(l_hChildThread); cout<<"子线程工作完成"<<endl; return 0; } DWORD WINAPI ThreadFunc(LPVOID) { g_Mutex.Lock(); cout<<"子线程工作中..."<<endl; Sleep(1000); g_Mutex.Unlock(); return 0; }
之所以写这篇blog,是因为被CSingleLock弄的有点概念不清,后面明白了,CSingleLock只是进行了再一次的封装。举个例子。有点类似autoptr,弄一层封装,用于解决下面这样的问题,若函数返回点很多,这样写会让人抓狂.
g_Mutex.Lock(); if (false) { g_Mutex.Unlock(); return false; } g_Mutex.Unlock();
如果用CSingleLock则是这样
CSingleLock(&g_Mutex, TRUE); if (false) { return false; }
先看下CSingleLock的构造函数:首先进行运行时类型识别,是否CSyncObject类型,此外还将Mutex的(或者Event等等的)Handle传递给CSingleLock对象.并用m_pObject成员变量拷贝pObject指针,用以调用CMutex CEvent等等的Lock Unlock函数.若bInitialLock设置为TRUE,则省去了调用Lock这一步.构造函数中替你调用了.
CSingleLock::CSingleLock(CSyncObject* pObject, BOOL bInitialLock) { ASSERT(pObject != NULL); ASSERT(pObject->IsKindOf(RUNTIME_CLASS(CSyncObject))); if(pObject == NULL) AfxThrowInvalidArgException(); m_pObject = pObject; m_hObject = pObject->m_hObject; m_bAcquired = FALSE; if (bInitialLock) Lock(); }
如下为,CSingleLock的析构函数,调用了Unlock那么,CSingleLock局部对象l_oSingleLock超出其作用域时,将调用l_oSingleLock的析构函数释放对CMutex CEvent CSemaphore的所有权, CSingleLock不但起到了一个autoptr的作用,还通过封装的方式让CMutex CEvent的使用方式一致.
_AFXMT_INLINE ::CSingleLock::~CSingleLock() { Unlock(); }