Как избежать recursive_mutex

0

У меня есть случай 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 в приведенном выше примере кода, так как mutex блокируется дважды в том же потоке, когда вызывается Shutdown.

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

благодаря,

Теги:
multithreading
boost
synchronization
recursive-mutex

1 ответ

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

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

  • 0
    Спасибо, это было полезно, но просто.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню