如何避免recursive_mutex

时间:2014-11-14 11:38:54

标签: c++ multithreading boost synchronization recursive-mutex

我有一个recursive_mutex的例子,我正试图解决。以下是解释问题的代码。

 void OnConnectionDisconnected()
    {
        boost::lock_guard<boost::mutex> lock ( m_mutexConnectionSet );      
        IPCSyncConnectionSharedPtrSet::iterator it =      m_IPCSyncConnectionSet.find(spConnection);
        if ( it != m_IPCSyncConnectionSet.end())
        {   
            m_IPCSyncConnectionSet.erase(*it);      
        }
    }

    void ShutdownServer()
    {
        boost::lock_guard<boost::mutex> lock ( m_mutexConnectionSet );      
        IPCSyncConnectionSharedPtrSet::iterator it = m_IPCSyncConnectionSet.begin();    
        for (; it != m_IPCSyncConnectionSet.end(); )
        {
            if (*it) 
            {
                IPCSyncConnectionSharedPtr spIPCConnection = (*it);
                it++;

                //This call indirectly calls OnConnectionDisconnected and erase the connection.
                spIPCConnection->Disconnect();
            }
            else 
            {
                ++it;
            }
        }
    }

在多个线程(n)上调用OnConnectionDisconnected,以及在连接处于活动状态或断开连接时,只在一个线程上调用ShutdownServer。 ShutdownServer遍历所有连接,并在每个连接上调用Disconnect,间接调用OnConnectionDisconnected,我实际上擦除了连接。我在访问m_IPCSyncConnectionSet之前锁定了互斥锁,因为在其他线程中修改了连接集。

我需要在上面的示例代码中使用recursive_mutex,因为当调用Shutdown时,互斥锁会在同一个线程上被锁定两次。

有谁能建议我如何解决上述问题并避免recursive_lock? recurive_mutex将根据本文http://www.fieryrobot.com/blog/2008/10/14/recursive-locks-will-kill-you/

杀死你

感谢,

1 个答案:

答案 0 :(得分:2)

ShutdownServer()处理容器的临时副本。除了锁定问题之外,迭代一个被另一个函数修改的容器也不是一个好主意(即使这个特定的容器类型在擦除一个元素时没有使所有的迭代器无效,这样的代码也会相当脆弱而且不必要地复杂化。)

void ShutdownServer()
{
    boost::lock_guard<boost::mutex> lock ( m_mutexConnectionSet );
    auto connections = m_IPCSyncConnectionSet;
    lock.unlock();
    for (auto it = connections.begin(); it != connections.end(); ++it)
      if (*it) 
        (*it)->Disconnect();
}

现在你既不需要关心锁定也不关心迭代器的有效性。