Я работаю над рефакторингом некоторого устаревшего кода, который страдает от взаимоблокировок. Есть две основные первопричины:
1) один и тот же поток несколько раз блокирует один и тот же мьютекс, что нетрудно разрешить, и 2) код время от времени вызывает определенные пользователем функции, которые могут вводить один и тот же код на верхнем уровне. Мне нужно заблокировать мьютекс перед вызовом пользовательских функций, но я могу снова выполнить тот же код, что приведет к тупиковой ситуации. Итак, мне нужен какой-то механизм, чтобы сказать мне, что мьютекс уже заблокирован, и я не должен блокировать его снова. Какие-либо предложения?
Вот (очень) краткое изложение того, что делает код:
class TreeNode {
public:
// Assign a new value to this tree node
void set(const boost::any& value, boost::function<void, const TreeNode&> validator) {
boost::upgrade_lock<boost::shared_mutex> lock(mutexToTree_);
// call validator here
boost::upgrade_to_unique_lock<boost::shared_mutex> ulock(lock);
// set this TreeNode to value
}
// Retrieve the value of this tree node
boost::any get() {
boost::shared_lock<boost::shared_mutex> lock(mutexToTree_);
// get value for this tree node
}
private:
static boost::shared_mutex mutexToRoot_;
};
Проблема в том, что функция валидатора может вызывать get()
, что блокирует mutexToRoot_
в том же потоке. Я мог бы изменить mutexToRoot_
, чтобы он был рекурсивным мьютексом, но это помешало бы другим потокам читать дерево во время операции get()
, что является нежелательным поведением.