Mysterious QMutex destroying locked mutex
-
Hi mates
I got that warning (and application crash) for the following code:
for (const QString &video : videoFiles) { ThumbnailExtractor *extractor = new ThumbnailExtractor(counter, folderPath + '/' + video); QThread *thread = new QThread(); extractor->moveToThread(thread); connect(thread, SIGNAL(started()), extractor, SLOT(generateThumbnail()), Qt::QueuedConnection); connect(extractor, SIGNAL(finished()), thread, SLOT(quit()), Qt::QueuedConnection); //automatically delete thread and thumbnail extractor object when work is done connect(extractor, SIGNAL(finished()), extractor, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); }
ThumbnailExtractor is not using QMutex at all, the crashing one comes from QThread. What I've messed up?
-
@MasterBLB said in Mysterious QMutex destroying locked mutex:
ThumbnailExtractor is not using QMutex at all, the crashing one comes from QThread. What I've messed up?
I seems to me that
ThumbnailExtractor
have QObject based members which are created in constructor but which stays in current thread.Are you sure all QObject base members for this class are created in
generateThumbnail()
or have the class instance as parent? -
Indeed it has:
class ThumbnailExtractor : public QObject { Q_OBJECT .... private: QMediaPlayer *player; ThumbailVideoSurface *surface; QMediaContent content;//that's not a descendant of QObject ..... };
however, in the constructor I have:
ThumbnailExtractor::ThumbnailExtractor(int counter, const QString &videoFilePath, QObject *parent) : QObject(parent), content(videoFilePath) { player = new QMediaPlayer(this); surface = new ThumbailVideoSurface(counter, this); player->setVideoOutput(surface); connect(surface, SIGNAL(stopMedia()), player, SLOT(stop()), Qt::QueuedConnection); connect(surface, SIGNAL(stopMedia()), this, SIGNAL(finished()), Qt::QueuedConnection); player->setMuted(true); connect(player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(error(QMediaPlayer::Error)));//, Qt::QueuedConnection); connect(player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(mediaStatusChanged(QMediaPlayer::MediaStatus)));//, Qt::QueuedConnection); }
so yeah, these should be moved to another thread along with ThumbnailExtractor object.
-
@MasterBLB said in Mysterious QMutex destroying locked mutex:
so yeah, these should be moved to another thread along with ThumbnailExtractor object.
What about
ThumbailVideoSurface
? -
@KroMignon said in Mysterious QMutex destroying locked mutex:
@MasterBLB said in Mysterious QMutex destroying locked mutex:
so yeah, these should be moved to another thread along with ThumbnailExtractor object.
What about
ThumbailVideoSurface
?It does not contain any member variables.
EDIT:
Wrong! It has just one int member; I meant it does not contain any QObject-related members. -
@MasterBLB said in Mysterious QMutex destroying locked mutex:
it does not contain any QObject-related members.
Given the name, are you by any chance using
QPixmap
in it?From https://doc.qt.io/qt-5/thread-basics.html#gui-thread-and-worker-thread
All widgets and several related classes, for example QPixmap, don't work in secondary threads.
-
I'm using QImage:
bool ThumbailVideoSurface::present(const QVideoFrame &frame) { if (frame.isValid()) { QImage thumbnail(frame.image()); thumbnail.save("thumbnail" + QString::number(tempCounter) + ".png");//that's only temporary, finally I'm going to create some kind of QMap <fileName, thumbnail QPixmap/QImage> //stop();//to wykrzacza aplikacjÄ™ emit stopMedia(); } return true; }
but I was going to switch to QPixmap later on, for rescaling the image.
-
@MasterBLB said in Mysterious QMutex destroying locked mutex:
ThumbnailExtractor is not using QMutex at all, the crashing one comes from QThread. What I've messed up?
You don't wait for the thread to finish from what I can tell. Also when diagnosing crashes, please provide a stack trace.
-
A try to check stack frame was the 1st I've tried before writing the post, sadly there is none. Besides, pls explain me how I don't wait for the thread to stop before deleting if I have the lines:
connect(extractor, SIGNAL(finished()), thread, SLOT(quit()), Qt::QueuedConnection); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
-
@MasterBLB said in Mysterious QMutex destroying locked mutex:
A try to check stack frame was the 1st I've tried before writing the post, sadly there is none.
If you don't have a stack trace, then the program is not running. There's no crash without a stack is the point. If you simply get a warning from the Qt runtime, then run your program in the debuger with the environment variable
QT_FATAL_WARNINGS
set to1
so it trips at the point of the actual error and then extract the stack trace.Besides, pls explain me how I don't wait for the thread to stop before deleting if I have the lines:
QThread::wait
(equivalent tostd::thread::join
) comes to mind. The fact that a signal was raised doesn't mean that the thread (which is simply a 'special' function) has finished executing. -
@kshegunov said in Mysterious QMutex destroying locked mutex:
If you don't have a stack trace, then the program is not running. There's no crash without a stack is the point. If you simply get a warning from the Qt runtime, then run your program in the debuger with the environment variable QT_FATAL_WARNINGS set to 1 so it trips at the point of the actual error and then extract the stack trace.
I mean there is no readable/useful stack frame, neither I don't know which of over 100 threads listed in debugger is the one I should check.
I tried that QT_FATAL_WARNINGS before, sadly due to some crap with QML ("QML QQuickText: Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.") I won't even reach the code part which contains threads.
-
Humor me, will you?
constexpr int poolSize = 16; QVector<QThread *> threadPool(poolSize); QCoreApplication * app = QCoreApplication::instance(); for (size_t i = 0; i < poolSize; i++) { QThread * thread = new QThread(app); thread->start(); QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); } QObject::connect(app, &QCoreApplication::aboutToQuit, [threadPool] () -> void { for (QThread * thread : threadPool) { thread->quit(); thread->wait(); } }); int index = 0; for (const QString &video : videoFiles) { ThumbnailExtractor *extractor = new ThumbnailExtractor(counter, folderPath + '/' + video); extractor->moveToThread(threadPool[index++ % poolSize]); QObject::connect(extractor, &ThumbnailExtractor::finished, extractor, &QObject::deleteLater); QMetaObject::invokeMethod(extractor, &ThumbnailExtractor::generateThumbnail, Qt::QueuedConnection); }
A note here:
QMediaPlayer
and related classes don't seem to be reentrant so you can't use them from different threads. Stick to the main one.