我们有互斥体对象的包装器。该包装器的构造函数创建一个互斥体。它还具有 Enter 和 Leave 函数,基本上调用 WaitForSingleObject 和 ReleaseMutex 。
现在程序线程正在执行多个函数,例如
void A()
{
mutexObj->Enter();
B();
mutexObj->Leave();
}
void B()
{
mutexObj->Enter();
C();
mutexObj->Leave();
}
Run Code Online (Sandbox Code Playgroud)
我看到线程在 B() 函数处停止。我读到的有关互斥体的内容是,我们可以从同一线程多次调用 WaitforSingleObjects,这就是为什么我的代码被阻塞的原因。
这是互斥锁的实现
CMutex::CMutex(const TCHAR *name)
: m_hMutex(CreateMutex(NULL, FALSE, name))
{
}
CMutex::~CMutex()
{
if (m_hMutex != NULL)
{
CloseHandle(m_hMutex);
m_hMutex= NULL;
}
}
bool Enter(DWORD milli= INFINITE){
HANDLE handles[1]= { m_hMutex };
return(MsgWaitForMultipleObjects(1,handles,FALSE, milli,QS_ALLINPUT) == WAIT_OBJECT_0);
}
void Leave(){ReleaseMutex(m_hMutex);}
Run Code Online (Sandbox Code Playgroud)
是的,互斥锁可以在同一线程中等待多次。文档说了这么多:
线程获得互斥锁的所有权后,它可以在重复调用等待函数时指定相同的互斥锁,而不会阻止其执行。这可以防止线程在等待它已经拥有的互斥体时发生死锁。要在这种情况下释放其所有权,每次互斥量满足等待函数的条件时,线程都必须调用一次 ReleaseMutex。
话虽这么说,您的代码并不安全,因为您忽略了等待的结果,因此在访问受互斥锁保护的内容之前,您无法确保您实际上拥有互斥锁。
试试这个:
class CMutex
{
public:
CMutex(const TCHAR *name = NULL);
~CMutex();
bool Enter(DWORD milli = INFINITE);
void Leave();
};
CMutex::CMutex(const TCHAR *name)
: m_hMutex(CreateMutex(NULL, FALSE, name))
{
}
CMutex::~CMutex()
{
if (m_hMutex != NULL)
{
CloseHandle(m_hMutex);
m_hMutex = NULL;
}
}
bool CMutex::Enter(DWORD milli)
{
return (WaitForSingleObject(m_hMutex, milli) == WAIT_OBJECT_0);
}
void CMutex::Leave()
{
ReleaseMutex(m_hMutex);
}
Run Code Online (Sandbox Code Playgroud)
void A()
{
if (mutexObj->Enter()) // <-- CHECK THE RESULT!!!
{
B();
mutexObj->Leave();
}
}
void B()
{
if (mutexObj->Enter()) // <-- CHECK THE RESULT!!!
{
C();
mutexObj->Leave();
}
}
Run Code Online (Sandbox Code Playgroud)
我会更进一步,使用 RAII 来管理锁:
class CMutex
{
public:
CMutex(const TCHAR *name = NULL);
~CMutex();
bool Enter(DWORD milli = INFINITE);
void Leave();
class Lock
{
private:
CMutex &m_mutex;
bool m_locked;
public:
Lock(CMutex &mutex);
~Lock();
bool isLocked() const;
};
};
CMutex::CMutex(const TCHAR *name)
: m_hMutex(CreateMutex(NULL, FALSE, name))
{
}
CMutex::~CMutex()
{
if (m_hMutex != NULL)
{
CloseHandle(m_hMutex);
m_hMutex = NULL;
}
}
bool Enter(DWORD milli)
{
return (WaitForSingleObject(m_hMutex, milli) == WAIT_OBJECT_0);
}
void Leave()
{
ReleaseMutex(m_hMutex);
}
CMutex::Lock::Lock(CMutex &mutex)
: m_mutex(mutex), m_locked(mutex.Enter())
{
}
CMutex::Lock::~Lock()
{
if (m_locked)
{
m_mutex.Leave();
m_locked = false;
}
}
CMutex::Lock::isLocked() const
{
return m_locked;
}
Run Code Online (Sandbox Code Playgroud)
void A()
{
CMutex::Lock lock(*mutexObj);
if (lock.isLocked()) // <-- CHECK THE RESULT!!!
B();
}
void B()
{
CMutex::Lock lock(*mutexObj);
if (lock.isLocked()) // <-- CHECK THE RESULT!!!
C();
}
Run Code Online (Sandbox Code Playgroud)
甚至:
class CMutex
{
public:
CMutex(const TCHAR *name = NULL);
~CMutex();
bool Enter(DWORD milli = INFINITE);
void Leave();
class Lock
{
private:
CMutex &m_mutex;
public:
Lock(CMutex &mutex);
~Lock();
};
};
CMutex::CMutex(const TCHAR *name)
: m_hMutex(CreateMutex(NULL, FALSE, name))
{
if (!m_hMutex)
throw std::runtime_error("cannot create the mutex handle");
}
CMutex::~CMutex()
{
CloseHandle(m_hMutex);
m_hMutex = NULL;
}
bool Enter(DWORD milli)
{
return (WaitForSingleObject(m_hMutex, milli) == WAIT_OBJECT_0);
}
void Leave()
{
ReleaseMutex(m_hMutex);
}
CMutex::Lock::Lock(CMutex &mutex)
: m_mutex(mutex)
{
if (!m_mutex.Enter())
throw std::runtime_error("cannot lock the mutex");
}
CMutex::Lock::~Lock()
{
m_mutex.Leave();
}
Run Code Online (Sandbox Code Playgroud)
void A()
{
CMutex::Lock lock(*mutexObj);
B();
}
void B()
{
CMutex::Lock lock(*mutexObj);
C();
}
Run Code Online (Sandbox Code Playgroud)