我们可以从单线程为Mutex多次调用WaitForSingleObject

我们有互斥对象的封装。这个封装器的构造器创建一个互斥锁。 它也有Enter和Leave函数,它们基本上调用了WaitForSingleObject和ReleaseMutex。

现在程序线程正在执行多个函数

void A()
{
  mutexObj->Enter();
  B();
  mutexObj->Leave();
}

void B()
{
  mutexObj->Enter();
  C();
  mutexObj->Leave();
}

我看到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);}

是的,一个互斥体可以在同一个线程中多次等待。 该文件同样表示:

线程获得互斥锁的所有权后,可以在对等待函数的重复调用中指定相同的互斥锁,而不会阻止其执行。 这可以防止线程在等待它已经拥有的互斥体时发生死锁。 为了在这种情况下释放它的所有权,每次互斥体满足等待函数的条件时,线程必须调用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);
}

void A()
{
    if (mutexObj->Enter()) // <-- CHECK THE RESULT!!!
    {
        B();
        mutexObj->Leave();
    }
}

void B()
{
    if (mutexObj->Enter()) // <-- CHECK THE RESULT!!!
    {
        C();
        mutexObj->Leave();
    }
}

通过使用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;
}

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();
}

甚至:

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();
}

void A()
{
    CMutex::Lock lock(*mutexObj);
    B();
}

void B()
{
    CMutex::Lock lock(*mutexObj);
    C();
}
链接地址: http://www.djcxy.com/p/62473.html

上一篇: can we call WaitForSingleObject multiple times from single thread for Mutex

下一篇: How soon will Windows OS be able to wake from a wake timer?