Класс recursive_mutex
Класс recursive_mutex представляет собой рекурсивный мьютекс.
В отличие от обычного mutex, он позволяет одному и тому же
потоку захватывать блокировку несколько раз подряд. Каждый успешный
вызов lock или try_lock увеличивает внутренний счётчик
владения, а каждый вызов unlock уменьшает его. Поток освобождает
мьютекс только тогда, когда счётчик достигнет нуля.
Это удобно в рекурсивных функциях, когда одна и та же функция,
захватившая мьютекс, вызывает себя или другую функцию, которая
снова пытается захватить тот же мьютекс. Обычный mutex
в такой ситуации приведёт к взаимоблокировке, а recursive_mutex -
нет. У класса нет конструктора с параметрами, он создаётся по умолчанию.
Синтаксис
#include <mutex>
std::recursive_mutex mtx;
mtx.lock();
mtx.try_lock();
mtx.unlock();
Пример
Давайте захватим рекурсивный мьютекс несколько раз в одном потоке и убедимся, что взаимоблокировки не происходит:
#include <iostream>
#include <mutex>
using namespace std;
int main()
{
recursive_mutex mtx;
mtx.lock();
cout << "first lock" << endl;
mtx.lock();
cout << "second lock" << endl;
mtx.unlock();
cout << "first unlock" << endl;
mtx.unlock();
cout << "second unlock" << endl;
return 0;
}
Результат выполнения кода:
"first lock"
"second lock"
"first unlock"
"second unlock"
Пример
Давайте напишем рекурсивную функцию, которая захватывает
recursive_mutex на каждом уровне рекурсии и считает сумму
чисел от 1 до 5:
#include <iostream>
#include <mutex>
using namespace std;
recursive_mutex mtx;
int sum(int n)
{
mtx.lock();
if (n <= 0)
{
mtx.unlock();
return 0;
}
int res = n + sum(n - 1);
mtx.unlock();
return res;
}
int main()
{
cout << sum(5) << endl;
return 0;
}
Результат выполнения кода:
15
Пример
Давайте проверим работу метода try_lock при повторном
захвате мьютекса тем же потоком:
#include <iostream>
#include <mutex>
using namespace std;
int main()
{
recursive_mutex mtx;
mtx.lock();
if (mtx.try_lock())
{
cout << "try_lock success" << endl;
mtx.unlock();
}
else
{
cout << "try_lock failed" << endl;
}
mtx.unlock();
return 0;
}
Результат выполнения кода:
"try_lock success"