Как использовать рекурсивный QMutex

Я пытаюсь использовать рекурсивный QMutex, я читаю Справочник по классам QMutex, но я не понимаю, как это сделать, может кто-нибудь дать мне пример?
Мне нужен какой-то способ блокировки QMutex, который можно разблокировать после или до вызова метода блокировки.
Если рекурсивный мьютекс не является способом, есть ли другой путь?

4

Решение

Чтобы создать рекурсивный QMutex, вы просто передаете QMutex::Recursive во время строительства, например:

QMutex mutex(QMutex::Recursive);
int number = 6;

void method1()
{
mutex.lock();
number *= 5;
mutex.unlock();
}

void method2()
{
mutex.lock();
number *= 3;
mutex.unlock();
}

Recursive означает, что вы можете заблокировать мьютекс несколько раз из одного потока, вам не нужно его разблокировать. Если я правильно понял твой вопрос, это то, что ты хочешь.

Будьте осторожны, если вы делаете рекурсивную блокировку, вы должны вызывать unlock одинаковое количество раз. Лучший способ заблокировать / разблокировать мьютекс — использовать QMutexLocker

#include <QMutexLocker>

QMutex mutex(QMutex::Recursive);
int number = 6;

void method1()
{
QMutexLocker locker(&mutex); // Here mutex is locked
number *= 5;
// Here locker goes out of scope.
// When locker is destroyed automatically unlocks mutex
}

void method2()
{
QMutexLocker locker(&mutex);
number *= 3;
}
7

Другие решения

Рекурсивный мьютекс может быть заблокирован несколько раз из одного потока без необходимости разблокировки, если из одного и того же потока выполняется одинаковое количество вызовов разблокировки. Этот механизм удобен, когда совместно используемый ресурс используется более чем одной функцией, и одна из этих функций вызывает другую функцию, в которой используется ресурс.

Рассмотрим следующий класс:

class Foo {
public:
Foo();
void bar();    // Does something to the resource
void thud();   // Calls bar() then does something else to the resource
private:
Resource mRes;
QMutex mLock;
}

Начальная реализация может выглядеть примерно так:

Foo::Foo() {}

void Foo::bar() {
QMutexLocker locker(&mLock);
mRes.doSomething();
}

void Foo::thud() {
QMutexLocker locker(&mLock);
bar();
mRes.doSomethingElse();
}

Приведенный выше код будет DEADLOCK при вызовах Thud. mLock будет получен в первой строке thud () и еще раз первой строкой bar (), которая будет блокировать ожидание thud (), чтобы снять блокировку.

Простым решением было бы сделать рекурсивную блокировку в ctor.

Foo::Foo() : mLock(QMutex::Recursive) {}

Это исправление ОК, которое подойдет для многих ситуаций, однако следует помнить, что использование этого решения может привести к снижению производительности, поскольку при каждом рекурсивном вызове мьютекса может потребоваться системный вызов для идентификации текущего идентификатора потока.

В дополнение к проверке идентификатора потока, все вызовы thud () все еще выполняют QMutex :: lock () дважды!

Проекты, которые требуют рекурсии, могут быть в состоянии подвергнуться рефакторингу, чтобы устранить потребность в рекурсивном мьютексе. В целом, необходимость в рекурсивном мьютексе является «запахом кода» и указывает на необходимость придерживаться принципа разделения интересов.

Для класса Foo можно представить создание вызова частной функции, которая выполняет совместное вычисление и поддерживает блокировку ресурса на уровне открытого интерфейса.

class Foo {
public:
Foo();
void bar();    // Does something to the resource
void thud();   // Does something then does something else to the resource
private:
void doSomething();
private:
Resource mRes;
QMutex mLock;
}

Foo::Foo() {}

// public
void Foo::bar() {
QMutexLocker locker(&mLock);
doSomething();
}

void Foo::thud() {
QMutexLocker locker(&mLock);
doSomething();
mRes.doSomethingElse();
}

// private
void Foo::doSomething() {
mRes.doSomething();        // Notice - no mutex in private function
}
3

Рекурсивный режим просто означает, что если поток владеет мьютексом, и тот же поток пытается снова заблокировать мьютекс, это будет успешно выполнено. Требование заключается в том, что звонки lock/unlock сбалансированы.

В нерекурсивном режиме это приведет к тупику.

2
По вопросам рекламы [email protected]