Qmutex destroying locked mutex что значит майнинг
Qmutex destroying locked mutex что значит майнинг
I have used Qmutex in my project and when i close the application getting an crash saying «destroying locked mutex». Then i removed the use of mutex variables and then also i am getting the same error. I have used threads in my application and quitting them once work is done. Not sure from where i am getting this mutex error.
I have used QSharedmemory in my application to make the application to have only one instance at a given point of time. Even i removed that, but still getting the error.
Please suggest us how we can solve this issue.
Thanks & Regards,
Pradeep
@Pradeep-NS The error message tells you what the problem is: you are destroying a locked mutex. So, when your app is closed there is a locked mutex which then destroyed. You need to make sure you unlock the mutex when exiting the application.
Please also check documentation: https://doc.qt.io/qt-5/qmutex.html#dtor.QMutex
@jsulm Even i have removed the usage of mutex from my application, but still getting this error message
@Pradeep-NS Are you sure you removed all mutexes?
Did you do a complete rebuild of your application (delete build folder, run qmake and build)?
Also if your app is crashing you can run it in debugger and check the stack trace to see where exactly it is crashing (use debug build).
Run with QT_FATAL_WARNINGS environment variable set and extract a stack trace. Paste it here.
Многопоточность, общие данные и мьютексы
Введение
При написании многопоточных приложений почти всегда требуется работать с общими данными, одновременное изменение которых может привести к очень неприятным последствиям.
Для блокировки общих данных от одновременного доступа необходимо использовать объекты синхронизации.
В данном топике рассмотренна методика работы с мютексами, существенно уменьшающая количество потенциальных ошибок связанных с созданием/удалением и захватом/освобождением.
Неудаление мютекса приводит к утечке памяти, незахват — к некорректным данным, а неосвобождение — к блокировке всех функций, работающих с общими данными.
Ниже рассматривается работа с мютексами в Windows и Unix, подобная идея может быть использована при работе с другими объектами синхронизации.
Эта идея является частным случаем методики «Выделение ресурса — есть инициализация (RAII)».
Создание, настройка и удаление мютекса
Для начала объявим класс CAutoMutex, который создает мютекс в конструкторе и удаляет в деструторе.
Плюсы:
— не нужно плодить по всему проекту похожие фрагменты коды инициализации, настройки и удаления мютекса
— автоматическое удаление мютекса и освобождение ресурсов, занятых им
// класс-оболочка, создающий и удаляющий мютекс (Windows)
class CAutoMutex
<
// дескриптор создаваемого мютекса
HANDLE m_h_mutex;
// запрет копирования
CAutoMutex( const CAutoMutex&);
CAutoMutex& operator =( const CAutoMutex&);
public :
CAutoMutex()
<
m_h_mutex = CreateMutex(NULL, FALSE, NULL);
assert(m_h_mutex);
>
В Windows мютексы по умолчанию рекурсивные, а в Unix — нет. Если мютекс не является рекурсивным, то попытка захватить его два раза в одном потоке приведет к deadlock-у.
Чтобы в Unix создать рекурсивный мютекс, необходимо установить соответствующий флаг при инициализации. Соответствующий класс CAutoMutex выглядел бы так (проверки возвращаемых значений не показаны для компактности):
// класс-оболочка, создающий и удаляющий рекурсивный мютекс (Unix)
class CAutoMutex
<
pthread_mutex_t m_mutex;
public :
CAutoMutex()
<
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m_mutex, &attr);
pthread_mutexattr_destroy(&attr);
>
Захват и освобождение мютекса
По аналогии с предыдущим классом объявим класс CMutexLock, который занимает мютекс в конструкторе и освобождает в деструкторе. Созданный объект этого класса автоматически захватит мютекс и освободит его в конце области действия независимо от того, какой именно был выход из этой области: нормальный выход, преждевременный return или выброс исключения. Плюсом также является, что можно не плодить похожие фрагменты кода работы с мютексами.
// класс-оболочка, занимающий и освобождающий мютекс
class CMutexLock
<
HANDLE m_mutex;
// запрещаем копирование
CMutexLock( const CMutexLock&);
CMutexLock& operator =( const CMutexLock&);
public :
// занимаем мютекс при конструировании объекта
CMutexLock(HANDLE mutex): m_mutex(mutex)
<
const DWORD res = WaitForSingleObject(m_mutex, INFINITE);
assert(res == WAIT_OBJECT_0);
>
// освобождаем мютекс при удалении объекта
Для еще большего удобства объявим следующий макрос:
Макрос позволяет не держать в голове имя класса CMutexLock и его пространство имен, а также не ломать голову каждый раз над названием создаваемого (например _tmp_mtx_capt) объекта.
Примеры использования
Рассмотрим примеры использования.
Для упрощения примера объявим мютекс и общие данные в глобальной области:
// автоматически создаваемый и удаляемый мютекс
static CAutoMutex g_mutex;
Пример простой функции, использующей общие данные и макрос SCOPE_LOCK_MUTEX:
<
// занимаем мютекс
SCOPE_LOCK_MUTEX(g_mutex. get ());
// изменяем общие данные
g_common_cnt_ex = 0;
g_common_cnt = 0;
// здесь мютекс освобождается
>
Не правда ли, что функция do_sth_1() выглядит элегантнее, чем следующая? do_sth_1_eq:
void do_sth_1_eq( ) throw ()
<
// занимаем мютекс
if (WaitForSingleObject(g_mutex. get (), INFINITE) == WAIT_OBJECT_0)
<
// изменяем общие данные
g_common_cnt_ex = 0;
g_common_cnt = 0;
// надо не забыть освободить мютекс
ReleaseMutex(g_mutex. get ());
>
else
<
assert(0);
>
>
В следующем примере точек выхода из функции три, но упоминание о мютексе только одно (объявление области блокировки мютекса):
// занимаем мютекс на критическом участке
SCOPE_LOCK_MUTEX(g_mutex. get ());
if (rem == 1)
<
g_common_cnt_ex++;
// мютекс автоматически освободится при выбросе исключения
throw Ex();
>
else if (rem == 2)
<
// мютекс автоматически освободится при возврате
g_common_cnt++;
return 1;
>
Примечание: я не сторонник использовать несколько return-ов в одной функции, просто пример от этого
становится чуть показательнее.
А если бы функция была длиннее и точек выброса исключений было бы с десяток? Без макроса нужно было поставить перед каждой из них ReleaseMutex(. ), а ошибиться здесь можно очень легко.
Заключение
Приведенные примеры классов и макросов достаточно просты, они не содержат сложных проверок и ожидают освобождения мютекса в течение бесконечного времени. Но даже это облегчает жизнь во многих случаях. А если облегчает жизнь, то почему бы это не использовать?
UPD: Первый класс CAutoMutex по ошибке не был написан, вместо него было повторное объявление второго класса CMutexLock. Исправлено.
UPD2: Убраны слова inline в объявлении методов внутри классов за ненадобностью.
UPD3: Был добавлен вариант класса CAutoMutex с рекурсивным мютексом для Unix.
Qt Documentation
Contents
The QMutex class provides access serialization between threads. More.
Note: All functions in this class are thread-safe.
Public Types
Public Functions
QMutex()
Detailed Description
The purpose of a QMutex is to protect an object, data structure or section of code so that only one thread can access it at a time (this is similar to the Java synchronized keyword). It is usually best to use a mutex with a QMutexLocker since this makes it easy to ensure that locking and unlocking are performed consistently.
For example, say there is a method that prints a message to the user on two lines:
If these two methods are called in succession, the following happens:
If these two methods are called simultaneously from two threads then the following sequence could result:
If we add a mutex, we should get the result we want:
Then only one thread can modify number at any given time and the result is correct. This is a trivial example, of course, but applies to any other case where things need to happen in a particular sequence.
When you call lock() in a thread, other threads that try to call lock() in the same place will block until the thread that got the lock calls unlock(). A non-blocking alternative to lock() is tryLock().
QMutex is optimized to be fast in the non-contended case. A non-recursive QMutex will not allocate memory if there is no contention on that mutex. It is constructed and destroyed with almost no overhead, which means it is fine to have many mutexes as part of other classes.
Member Type Documentation
enum QMutex:: RecursionMode
Constant | Value | Description |
---|---|---|
QMutex::Recursive | 1 | In this mode, a thread can lock the same mutex multiple times and the mutex won’t be unlocked until a corresponding number of unlock() calls have been made. You should use QRecursiveMutex for this use-case. |
QMutex::NonRecursive | 0 | In this mode, a thread may only lock a mutex once. |
Member Function Documentation
QMutex:: QMutex ( QMutex::RecursionMode mode)
Constructs a new mutex. The mutex is created in an unlocked state.
If mode is QMutex::Recursive, a thread can lock the same mutex multiple times and the mutex won’t be unlocked until a corresponding number of unlock() calls have been made. Otherwise a thread may only lock a mutex once. The default is QMutex::NonRecursive.
Recursive mutexes are slower and take more memory than non-recursive ones.
QMutex:: QMutex ()
Constructs a new mutex. The mutex is created in an unlocked state.
QMutex::
Destroys the mutex.
Warning: Destroying a locked mutex may result in undefined behavior.
bool QMutex:: isRecursive () const
Returns true if the mutex is recursive.
This function was introduced in Qt 5.7.
void QMutex:: lock ()
Locks the mutex. If another thread has locked the mutex then this call will block until that thread has unlocked it.
Calling this function multiple times on the same mutex from the same thread is allowed if this mutex is a recursive mutex. If this mutex is a non-recursive mutex, this function will dead-lock when the mutex is locked recursively.
bool QMutex:: tryLock ( int timeout = 0)
Note: Passing a negative number as the timeout is equivalent to calling lock(), i.e. this function will wait forever until mutex can be locked if timeout is negative.
If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it.
Calling this function multiple times on the same mutex from the same thread is allowed if this mutex is a recursive mutex. If this mutex is a non-recursive mutex, this function will always return false when attempting to lock the mutex recursively.
bool QMutex:: try_lock ()
The function returns true if the lock was obtained; otherwise it returns false
This function was introduced in Qt 5.8.
Note: Passing a negative duration as the duration is equivalent to calling try_lock(). This behavior differs from tryLock().
If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it.
Calling this function multiple times on the same mutex from the same thread is allowed if this mutex is a recursive mutex. If this mutex is a non-recursive mutex, this function will always return false when attempting to lock the mutex recursively.
This function was introduced in Qt 5.8.
Note: Passing a timePoint which has already passed is equivalent to calling try_lock(). This behavior differs from tryLock().
If the lock was obtained, the mutex must be unlocked with unlock() before another thread can successfully lock it.
Calling this function multiple times on the same mutex from the same thread is allowed if this mutex is a recursive mutex. If this mutex is a non-recursive mutex, this function will always return false when attempting to lock the mutex recursively.
This function was introduced in Qt 5.8.
void QMutex:: unlock ()
Unlocks the mutex. Attempting to unlock a mutex in a different thread to the one that locked it results in an error. Unlocking a mutex that is not locked results in undefined behavior.
В© 2021 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.