У меня есть случай 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/
Спасибо,
В 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();
}
Теперь вам не нужно заботиться ни о блокировке, ни о валидности итераторов.