Как избежать 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;
            }
        }
    }

OnConnectionDisconnected вызывается в нескольких потоках (n), а ShutdownServer вызывается только в одном потоке в любое время, когда подключение активно или отключено. ShutdownServer перебирает все соединения и вызывает Disconnect для каждого, который косвенно вызывает OnConnectionDisconnected, где я фактически стираю соединение. Я заблокировал мьютекс перед доступом к m_IPCSyncConnectionSet, так как набор соединений изменяется в других потоках.

Мне нужно использовать recursive_mutex в приведенном выше примере кода, так как мьютекс блокируется дважды в одном и том же потоке, когда вызывается завершение работы.

Может кто-нибудь предложить, как я могу решить вышеупомянутую проблему и избежать recursive_lock? recurive_mutex убьет вас в соответствии с этой статьей http://www.fieryrobot.com/blog/2008/10/14/recursive-locks-will-kill-you/

Спасибо,

1 ответ

Решение

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

Теперь вам не нужно заботиться ни о блокировке, ни о валидности итераторов.

Другие вопросы по тегам