Класс QMutex
Класс QMutex обеспечивает сериализацию доступа между потоками. Подробнее...
| Заголовок: | #include <QMutex> |
| qmake: | QT += core |
| Наследует: | QBasicMutex |
| Наследуется от: |
Примечание: Все функции в этом классе являются безопасными для многопоточных операций.
Типы публичного доступа
| перечисление | RecursionMode { Recursive, NonRecursive } |
Функции публичного доступа
| QMutex(QMutex::RecursionMode mode) | |
| QMutex() | |
| ~QMutex() | |
| bool | isRecursive() const |
| void | lock() |
| bool | tryLock(int timeout = 0) |
| bool | try_lock() |
| bool | try_lock_for(std::chrono::duration<Rep, Period> duration) |
| bool | try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) |
| void | unlock() |
Подробное описание
Класс QMutex предназначен для защиты объекта, структуры данных или раздела кода, чтобы к нему мог получить доступ только один поток одновременно (это аналогично ключевому слову Java synchronized). Обычно лучше всего использовать mutex с QMutexLocker, так как это упрощает обеспечение последовательного выполнения блокировки и разблокировки.
Например, предположим, что есть метод, который выводит сообщение пользователю на две строки:
int number = 6;
void method1()
{
number *= 5;
number /= 4;
}
void method2()
{
number *= 3;
number /= 2;
} Если эти два метода вызываются последовательно, происходит следующее:
// method1() number *= 5; // number is now 30 number /= 4; // number is now 7 // method2() number *= 3; // number is now 21 number /= 2; // number is now 10
Если эти два метода вызываются одновременно из двух потоков, может получиться следующая последовательность:
// Thread 1 calls method1() number *= 5; // number is now 30 // Thread 2 calls method2(). // // Most likely Thread 1 has been put to sleep by the operating // system to allow Thread 2 to run. number *= 3; // number is now 90 number /= 2; // number is now 45 // Thread 1 finishes executing. number /= 4; // number is now 11, instead of 10
Если мы добавим mutex, мы должны получить желаемый результат:
QMutex mutex;
int number = 6;
void method1()
{
mutex.lock();
number *= 5;
number /= 4;
mutex.unlock();
}
void method2()
{
mutex.lock();
number *= 3;
number /= 2;
mutex.unlock();
} Тогда только один поток может изменять number в любой момент времени, и результат будет корректным. Это, конечно, тривиальный пример, но он применим к любому другому случаю, когда необходимо, чтобы действия выполнялись в определенной последовательности.
При вызове lock() в потоке другие потоки, которые пытаются вызвать lock() в том же месте, будут заблокированы до тех пор, пока поток, получивший блокировку, не вызовет unlock(). Неблокирующей альтернативой lock() является tryLock().
QMutex оптимизирован для быстрой работы в неконкурентном случае. Нерекурсивный QMutex не будет выделять память, если на этот mutex нет конкуренции. Он создается и уничтожается практически без накладных расходов, что означает, что можно иметь много mutex как часть других классов.
См. также QRecursiveMutex, QMutexLocker, QReadWriteLock, QSemaphore и QWaitCondition.
Документация по типам членов
перечисление QMutex::RecursionMode
| Постоянная | Значение | Описание |
|---|---|---|
QMutex::Recursive |
1 |
В этом режиме поток может многократно блокировать один и тот же mutex, и mutex не будет разблокирован до тех пор, пока не будет выполнено соответствующее количество вызовов unlock(). Для этого случая следует использовать QRecursiveMutex. |
QMutex::NonRecursive |
0 |
В этом режиме поток может заблокировать mutex только один раз. |
См. также QMutex() и QRecursiveMutex.
Документация по функциям-членам
void QMutex::unlock()
Разблокирует mutex. Попытка разблокировать mutex в другом потоке, нежели тот, который его заблокировал, приводит к ошибке. Разблокировка незаблокированного mutex приводит к неопределенному поведению.
См. также lock().
bool QMutex::try_lock_until(std::chrono::time_point<Clock, Duration> timePoint)
Попытка заблокировать mutex. Эта функция возвращает true если блокировка была получена; в противном случае она возвращает false. Если другой поток заблокировал mutex, эта функция будет ждать по крайней мере до timePoint, пока mutex не станет доступным.
Примечание: передача timePoint, который уже прошёл, эквивалентна вызову try_lock(). Это поведение отличается от tryLock().
Если блокировка была получена, mutex необходимо разблокировать с помощью unlock() перед тем, как другой поток сможет успешно его заблокировать.
Вызов этой функции несколько раз на одном mutex из одного и того же потока разрешён, если этот mutex является рекурсивным mutex. Если этот mutex является нерекурсивным mutex, эта функция *всегда* вернёт false при попытке рекурсивной блокировки mutex.
Эта документация была добавлена в Qt 5.8.
bool QMutex::try_lock_for(std::chrono::duration<Rep, Period> duration)
Попытка заблокировать mutex. Эта функция возвращает true если блокировка была получена; в противном случае она возвращает false. Если другой поток заблокировал mutex, эта функция будет ждать не менее duration, пока mutex не станет доступным.
Примечание: передача отрицательной продолжительности в качестве duration эквивалентна вызову try_lock(). Это поведение отличается от tryLock().
Если блокировка была получена, mutex необходимо разблокировать с помощью unlock() перед тем, как другой поток сможет успешно его заблокировать.
Вызов этой функции несколько раз на одном mutex из одного и того же потока разрешён, если этот mutex является рекурсивным mutex. Если этот mutex является нерекурсивным mutex, эта функция *всегда* вернёт false при попытке рекурсивной блокировки mutex.
Эта документация была добавлена в Qt 5.8.
bool QMutex::try_lock()
Попытка заблокировать mutex. Эта функция возвращает true если блокировка была получена; в противном случае она возвращает false.
Эта функция предоставлена для совместимости с концепцией Standard Library Lockable. Она эквивалентна tryLock().
Функция возвращает true если блокировка была получена; в противном случае она возвращает false
Эта документация была добавлена в Qt 5.8.
bool QMutex::tryLock(int timeout = 0)
Попытка заблокировать mutex. Эта функция возвращает true если блокировка была получена; в противном случае она возвращает false. Если другой поток заблокировал mutex, эта функция будет ждать не более timeout миллисекунд, пока mutex не станет доступным.
Примечание: передача отрицательного числа в качестве timeout эквивалентна вызову lock(), т. е. эта функция будет ждать вечно, пока mutex не будет заблокирован, если timeout отрицательный.
Если блокировка была получена, mutex необходимо разблокировать с помощью unlock() перед тем, как другой поток сможет успешно его заблокировать.
Вызов этой функции несколько раз на одном mutex из одного и того же потока разрешён, если этот mutex является рекурсивным mutex. Если этот mutex является нерекурсивным mutex, эта функция *всегда* вернёт false при попытке рекурсивной блокировки mutex.
void QMutex::lock()
Блокирует mutex. Если другой поток заблокировал mutex, этот вызов будет заблокирован до тех пор, пока этот поток не разблокирует его.
Вызов этой функции несколько раз на одном mutex из одного и того же потока разрешён, если этот mutex является рекурсивным mutex. Если этот mutex является нерекурсивным mutex, этот вызов приведёт к тупиковой ситуации, если mutex заблокирован рекурсивно.
См. также unlock().
QMutex::QMutex(QMutex::RecursionMode mode)
Создаёт новый mutex. Mutex создаётся в разблокированном состоянии.
Если mode равен QMutex::Recursive, поток может заблокировать тот же мьютекс несколько раз, и мьютекс не будет разблокирован, пока не будет выполнено соответствующее количество вызовов unlock(). В противном случае поток может заблокировать мьютекс только один раз. По умолчанию используется QMutex::NonRecursive.
Рекурсивные мьютексы медленнее и занимают больше памяти, чем нерекурсивные.
QMutex::QMutex()
Создаёт новый мьютекс. Мьютекс создаётся в разблокированном состоянии.
QMutex::~QMutex()
Удаляет мьютекс.
Предупреждение: Удаление заблокированного мьютекса может привести к неопределённому поведению.
bool QMutex::isRecursive() const
Возвращает true если мьютекс рекурсивный.
Эта функция была добавлена в Qt 5.7.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.14/qmutex.html