Я знаю, что если я заблокирую std::mutex дважды в одном потоке, это приведет к тупику.
Итак, я глобально заменил std::mutex на std::recursive_mutex.
Означает ли использование только std::recursive_mutex, что я никогда не столкнусь с тупиком?
Есть ли с этим какая-либо потенциальная проблема (кроме того, что он немного медленнее)?





Замена std::mutex на std::recursive_mutex помогает избежать взаимоблокировок из-за блокировки потока.
Это не гарантированное решение. Взаимоблокировки по-прежнему могут возникать из-за неправильного порядка блокировки или зависимостей от внешних ресурсов.
Используйте std::recursive_mutex только тогда, когда это действительно необходимо для рекурсивной блокировки. В противном случае рассмотрите альтернативы.
recursive_mutex решает проблему только тогда, когда потенциальный тупик вызван 1 потоком, которому требуется доступ к 1 защищенному ресурсу.
Вы все равно можете столкнуться с тупиком, используя recursive_mutex, если задействовано более одного ресурса.
Рассмотрим следующий сценарий, включающий два потока, которым требуется монопольный доступ к двум ресурсам (каждый из которых защищен мьютексом):
Классическое решение этого сценария состоит в том, что все потоки должны блокировать мьютексы в одном и том же порядке.
В качестве альтернативы, если это применимо в вашем случае, вы можете использовать std::lock для одновременной блокировки нескольких блокировок.
Более поздний подход может быть намного быстрее, как показано в статье Говарда Хиннанта: Обеденные философы: перезагрузка .
Или, если блокировки можно заблокировать в одном и том же месте кода, используйте std::lock . Эта статья показывает, что std::lock может быть значительно быстрее, чем наведение порядка.
@HowardHinnant, спасибо, добавил эту информацию в свой ответ.
Различные приказы или условия могут быть вашими врагами. Рассмотрим следующее (я использовал namespace std, чтобы навести порядок, хотя, как правило, это не лучшая практика):
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
recursive_mutex firstOne, secondOne;
void threadingOne() {
lock_guard<recursive_mutex> lock1(firstOne);
//pretend stuff happens
this_thread::sleep_for(chrono::milliseconds(100));
lock_guard<recursive_mutex> lock2(secondOne);
}
void threadingTwo() {
lock_guard<recursive_mutex> lock2(secondOne);
//this is stuff happening
this_thread::sleep_for(chrono::milliseconds(100));
lock_guard<recursive_mutex> lock1(firstOne);
}
int main() {
thread threadOne(threadingOne);
thread threadTwo(threadingTwo);
threadOne.join();
threadTwo.join();
cout << "This is not something you will see ever\n";
return 0;
}
Это связано с Будет ли recursive_mutex блокироваться при блокировке двумя потоками?, но этот вопрос касается случая, когда есть только один мьютекс, так что это не обман.