最近在多线程编程中多次使用到mutex来互斥,看了下项目的代码,有自己封装的mutex类,也有直接使用boost::mutex的,而boost中关于mutex可谓令人眼花撩换。这里总结一下。
对于mutex和lock,要明确一点,真正起到互斥作用的mutex,而lock可以认为是协助mutex令我们在使用时更方便。搞不清楚二者关系的可以参考这里:从高中一次半夜不冲厕所的经历谈程序
最基础的mutex的使用方法是这样的:
HANDLE g_mutex = NULL;
void test()
{
::WaitForSingleObject(g_mutex, INFINITE);
//do something...
ReleaseMutex(g_mutex);
}
使用匿名的互斥体,test函数中调用WaitForSingleObject等待其他线程释放g_mutex。INFINITE表示一直等待,也可以设置等待超时时间。
当前线程获得g_mutex后执行do something,之后释放g_mutex。
这里使用的是匿名互斥体,当然,在程序中需要多个互斥体时,可以通过CreateMutex创建命名互斥体,也可以通过OpenMutex打开一个互斥体。
不过很少有人像上面那样直接使用吧,太简单粗暴了,互斥体作为一个基本功能模块,怎么说也会封装一下,让别人用起来更爽些。如下是一个简单封装:
class MyMutex
{
public:
MyMutex()
:m_hMutex(NULL)
{
}
MyMutex(wchar_t* pMutexName)
:m_hMutex(NULL)
{
createMutex(pMutexName);
}
virtual ~MyMutex()
{
destroyMutex();
}
bool lock()
{
return m_hMutex ? (::WaitForSingleObject(m_hMutex,INFINITE) == WAIT_OBJECT_0) : false;
}
void unlock()
{
ReleaseMutex(m_hMutex);
}
bool createMutex(wchar_t* pMutexName)
{
if (m_hMutex)
{
return true;
}
m_hMutex = ::CreateMutex(NULL, FALSE, pMutexName);
return m_hMutex != NULL;
}
void destroyMutex()
{
CloseHandle(m_hMutex);
m_hMutex = NULL;
}
bool openMutex(wchar_t* pMutexName)
{
if (m_hMutex)
{
return true;
}
m_hMutex = ::OpenMutex(SYNCHRONIZE, FALSE, pMutexName);
return m_hMutex != NULL;
}
private:
HANDLE m_hMutex;
};
封装之后,就可以如下使用:
void test1()
{
MyMutex mutex;
mutex.createMutex(L"mutex_test_name1");
if (mutex.lock())
{
//do something...
mutex.unlock();
}
}
但是,就像 从高中一次半