How to correct use QtConcurrent::run
-
Hi,
In QML I've called this:
MenuItem { id: openLogMenuItem text: qsTr("Open...") shortcut: StandardKey.Open onTriggered: { if(openFileDialog !== null) { openFileDialog.accepted.connect(function () { manager.openFile(openFileDialog.fileUrl); manager.viewer.settingsManager.addRecentFile(openFileDialog.fileUrl.toString()); }); openFileDialog.open(); } } }
Also I've connected slot:
MdlManager { id: mdlManager onMdlLogParserDidStart: { spinnerView.running = true; cententViewLoader.setSource(""); } onMdlLogParserDidFinished: { spinnerView.running = false; if(parser !== null) { var options = { manager: loggerInfoView.mdl}; cententViewLoader.setSource("Components/MdlCentralWidget.qml", options); } } onMdlLogParserErrorDetected: { spinnerView.running = false; } }
In C++ I have method:
Q_INVOKABLE inline void openFile(QString file){m_lvManager->parseLogFile(file);}
And Connected slot:
m_lvManager = new MdlLogViewerManager(); m_lvManager->setParent(this); connect(m_lvManager->getParser(), &MdlLogParser::parserDidStart, this, [this]() { emit mdlLogParserDidStart(); }); connect(m_lvManager->getParser(), &MdlLogParser::parserDidFinished, this, [this](MdlLogParser* obj) { emit mdlLogParserDidFinished(obj); }); connect(m_lvManager->getParser(), &MdlLogParser::errorChanged, this, [this](MdlLogParserError* obj) { emit mdlLogParserErrorDetected(obj); }); connect(m_lvManager->getSettingsManager(), &ShavSettingsManager::settingsLoaded, this, [this](bool flag, ShavSettingsManager* settings) { emit mdlSettingsLoaded(flag, settings); });
And source code for method "parsingLogFile":
void MdlLogParser::parsingLogFile(QString fPath) { try { m_wasParsed = false; m_logFileFolder.clear(); m_logFilePath = fPath.replace("file://", ""); QString logFileName = m_logFilePath.split("/").last(); m_logFileFolder = m_logFilePath; m_logFileFolder.replace(logFileName, ""); m_classes.clear(); m_frameworksList.clear(); m_sessions.clear(); m_methods.clear(); m_messages.clear(); m_systemMessage.clear(); m_images.clear(); m_viewsStructures.clear(); emit parserDidStart(); QtConcurrent::run(this, &MdlLogParser::readLogFileContents); } catch(std::exception& exception) { ShavNotificationCenter::defaultManger()->postNotification(SHAV_NC_EXCEPTION_DETECTED, QVariant(exception.what())); } }
-
Hi, everyone!
I still have problem with threads in my project, but now it's strange and I don't know why this happens.
I've changed code in my project and now I have class which reading file, the content from file unzip and decoding using AES decode algorithm from QCA library. In result class generate QVariantMap object which return to main program by signal. The code of all operation looks like:
if(!m_logFilePath.isEmpty()) { m_logFilePath = m_logFilePath.replace("file://", ""); QFile file(m_logFilePath); if(file.exists()) { if(file.open(QIODevice::ReadOnly | QIODevice::Text)) { QTextStream stream(&file); QString content = stream.readAll(); if(!content.isNull()) { QByteArray compressedDatas = QByteArray::fromBase64(content.toUtf8()); QString fileContent = QString(uncompressDatas(compressedDatas)); //Trying to decompress source datas QString decodedString; if(!fileContent.isEmpty()) //If source datas was compressed. { decodedString = decode(fileContent, m_aesKey, m_aesIv); } else //If source datas doen't compressed we trying to decode withot decompress. { decodedString = decode(compressedDatas, m_aesKey, m_aesIv); } //Start convert to Objects if(!decodedString.isNull()) { QString crashString("Crash=Y"); bool wasCrash = false; if(decodedString.startsWith(crashString, Qt::CaseInsensitive)) { wasCrash = true; } decodedString = QString("[") + decodedString.mid(crashString.length(), decodedString.length()-crashString.length()-1) + QString("]"); QJsonDocument doc = QJsonDocument::fromJson(decodedString.toUtf8()); if(!doc.isEmpty()) { QVariant data = doc.toVariant(); QList<QVariant> list = data.toList(); if(!list.isEmpty()) { QVariantMap jsonObj, crashImage, startSession; QVariantList methods, viewsList, classes, messageList, systemsList, frameworks, images, loggerMessagesList, loggerExceptionsList, sessions; foreach(QVariant item, list) { QVariantMap obj = item.toMap(); QString componentType = obj.value(QString("componentType")).toString(); QString action = obj.value(QString("action")).toString(); if(componentType == QString("DeviceInfo")) { jsonObj["deviceInfo"] = obj; } else if(componentType == QString("ApplicationInfo")) { jsonObj["appInfo"] = obj; } else if(componentType == QString("LoggerInfo")) { jsonObj["loggerInfo"] = obj; } else if(componentType == QString("Crash")) { jsonObj["crashLog"] = obj; } else if(componentType == QString("StatisticObject")) { jsonObj["statistic"] = obj; } else if(componentType == QString("Method")) { methods.append(obj); } else if(componentType == QString("LibImages")) { frameworks = obj["list"].toList(); } else if(componentType == QString("Image")) { images.append(obj); bool isCrash = obj["forCrash"].toBool(); if(isCrash) { crashImage = obj; } } else if(componentType == QString("ViewStructure")) { viewsList.append(obj); } else if(componentType == QString("LoggerMessage")) { if(action == QString("Exception")) { loggerExceptionsList.append(obj); } else { loggerMessagesList.append(obj); } } else if(componentType == QString("Message")) { messageList.append(obj); } else if(componentType == QString("SystemMessage")) { systemsList.append(obj); } else if(componentType == QString("Class")) { classes.append(obj); } else if(componentType == QString("Session")) { if(action == QString("SessionStart")) { startSession = obj; } else if(action == QString("SessionFinished")) { QVariantMap map = startSession; map["start"] = startSession["timestamp"]; map["end"] = obj["timestamp"]; map["length"] = (obj["timestamp"].toDouble() - startSession["timestamp"].toDouble()); sessions.append(map); } } } QString path = m_logFilePath; QString logFile = m_logFilePath.split("/").last(); QString logFileFolder = path.replace(logFile, ""); jsonObj["logFilePath"] = m_logFilePath; jsonObj["logFileFolder"] = logFileFolder; jsonObj["logContent"] = decodedString; jsonObj["wasCrash"] = wasCrash; jsonObj["classes"] = classes; jsonObj["methods"] = methods; jsonObj["viewsStructures"] = viewsList; jsonObj["messages"] = messageList; jsonObj["systemMessage"] = systemsList; jsonObj["frameworksList"] = frameworks; jsonObj["images"] = images; jsonObj["sessions"] = sessions; QVariantMap crashLog = jsonObj["crashLog"].toMap(); crashLog["image"] = crashImage; jsonObj["crashLog"] = crashLog; QVariantMap loggerInfo = jsonObj["loggerInfo"].toMap(); loggerInfo["messages"] = loggerMessagesList; loggerInfo["exceptions"] = loggerExceptionsList; jsonObj["loggerInfo"] = loggerInfo; emit fileReaderDidFinish(jsonObj); } } } } } } } emit fileReaderDidFinish(QVariant());
When I need to use class I've called this code:
if(!file.isEmpty()) { emit m_parser->parserDidStart(); QThread* thread = new QThread(this); MdlFileReader* fileReader = new MdlFileReader(file, m_settingsManager->getAesKey(), m_settingsManager->getAesInventoryKey()); fileReader->moveToThread(thread); connect(fileReader, &MdlFileReader::fileReaderDidFinish, this, [this, file](QVariant jsonObj) { if(!jsonObj.isNull()) { m_parser->updateFromJSONObject(jsonObj); } }, Qt::QueuedConnection); connect(thread, &QThread::started, fileReader, &MdlFileReader::startParseFile); thread->start(); }
The problem is sometimes this code works and application does't crash. But sometimes application crashes. It's could happens every second time when I load application (without rebuild).
I've also tried QtConcurrent::run but no luck.
Full crash report looks like:
Process: MdlViewer [6460] Path: /Volumes/VOLUME/*/MdlViewer.app/Contents/MacOS/MdlViewer Identifier: com.shav.MdlViewer Version: 1.0.0 (1.0.0) Code Type: X86-64 (Native) Parent Process: Qt Creator [6229] Responsible: Qt Creator [6229] User ID: 501 Date/Time: 2015-03-13 20:35:02.729 +0200 OS Version: Mac OS X 10.10.2 (14C1510) Report Version: 11 Anonymous UUID: 01BBAAA2-2A09-5EF9-08B9-47ED5259279D Time Awake Since Boot: 39000 seconds Crashed Thread: 0 Dispatch queue: com.apple.main-thread Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: EXC_I386_GPFLT Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 org.qt-project.QtQml 0x000000010795c5ea QV4::QObjectWrapper::wrap(QV4::ExecutionEngine*, QObject*) + 42 1 org.qt-project.QtQml 0x000000010795ac72 QV4::QObjectWrapper::getProperty(QObject*, QV4::ExecutionContext*, QQmlPropertyData*, bool) + 1602 2 org.qt-project.QtQml 0x000000010795a41c QV4::QObjectWrapper::getQmlProperty(QV4::ExecutionContext*, QQmlContextData*, QV4::String*, QV4::QObjectWrapper::RevisionMode, bool*, bool) + 636 3 org.qt-project.QtQml 0x000000010795e266 QV4::QObjectWrapper::get(QV4::Managed*, QV4::String*, bool*) + 70 4 org.qt-project.QtQml 0x0000000107969f29 QV4::Runtime::getProperty(QV4::ExecutionContext*, QV4::ValueRef, QV4::String*) + 105 5 ??? 0x0000000112f7c9b9 0 + 4613196217 6 org.qt-project.QtQml 0x000000010791b190 QV4::SimpleScriptFunction::call(QV4::Managed*, QV4::CallData*) + 528 7 org.qt-project.QtQml 0x0000000107a0145e QQmlJavaScriptExpression::evaluate(QQmlContextData*, QV4::ValueRef, QV4::CallData*, bool*) + 622 8 org.qt-project.QtQml 0x00000001079a8142 QQmlBoundSignalExpression::evaluate(void**) + 2258 9 org.qt-project.QtQml 0x00000001079a8b68 QQmlBoundSignal_callback(QQmlNotifierEndpoint*, void**) + 440 10 org.qt-project.QtQml 0x00000001079e345c QQmlNotifier::emitNotify(QQmlNotifierEndpoint*, void**) + 92 11 org.qt-project.QtQml 0x0000000107984711 QQmlData::signalEmitted(QAbstractDeclarativeData*, QObject*, int, void**) + 753 12 org.qt-project.QtCore 0x0000000107467cb7 QMetaObject::activate(QObject*, int, int, void**) + 183 13 libqtquickcontrolsplugin.dylib 0x000000010fe15285 QQuickMenuItem::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 517 14 org.qt-project.QtCore 0x00000001074687ab QMetaObject::activate(QObject*, int, int, void**) + 2987 15 libqtquickcontrolsplugin.dylib 0x000000010fe12cfd QQuickAction::triggered(QObject*) + 61 16 libqtquickcontrolsplugin.dylib 0x000000010fe152a1 QQuickMenuItem::qt_static_metacall(QObject*, QMetaObject::Call, int, void**) + 545 17 org.qt-project.QtCore 0x0000000107461393 QObject::event(QEvent*) + 755 18 org.qt-project.QtWidgets 0x0000000107e2632b QApplicationPrivate::notify_helper(QObject*, QEvent*) + 251 19 org.qt-project.QtWidgets 0x0000000107e29648 QApplication::notify(QObject*, QEvent*) + 8136 20 org.qt-project.QtCore 0x0000000107436a5b QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) + 971 21 libqcocoa.dylib 0x000000010aea0b8e QCocoaEventDispatcherPrivate::processPostedEvents() + 190 22 libqcocoa.dylib 0x000000010aea1411 QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void*) + 33 23 com.apple.CoreFoundation 0x00007fff8f285681 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17 24 com.apple.CoreFoundation 0x00007fff8f27780d __CFRunLoopDoSources0 + 269 25 com.apple.CoreFoundation 0x00007fff8f276e3f __CFRunLoopRun + 927 26 com.apple.CoreFoundation 0x00007fff8f276858 CFRunLoopRunSpecific + 296 27 com.apple.HIToolbox 0x00007fff8e010aef RunCurrentEventLoopInMode + 235 28 com.apple.HIToolbox 0x00007fff8e01076e ReceiveNextEventCommon + 179 29 com.apple.HIToolbox 0x00007fff8e0106ab _BlockUntilNextEventMatchingListInModeWithFilter + 71 30 com.apple.AppKit 0x00007fff8c903f81 _DPSNextEvent + 964 31 com.apple.AppKit 0x00007fff8c903730 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194 32 com.apple.AppKit 0x00007fff8c8f7593 -[NSApplication run] + 594 33 libqcocoa.dylib 0x000000010aea02fd QCocoaEventDispatcher::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 2189 34 org.qt-project.QtCore 0x000000010743337d QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 381 35 org.qt-project.QtCore 0x000000010743635a QCoreApplication::exec() + 346 36 com.shav.MdlViewer 0x00000001067ebe57 main + 663 37 com.shav.MdlViewer 0x00000001067ebbb4 start + 52
What I do wrong? Thanks for the any help!
-
@shav Where is objects deletion?
http://doc.qt.io/qt-5/qthread.html Documentation contains very useful examles
-
@jalomic Thanks for the reply!
I've added the attribute to my main class which must separate thread as
/** Thread for read file.*/ QThread* m_thread;
In constructor of my class I've aded this line to create thread instance like this:
m_thread = new QThread(this);
and method where I'm using this thread looks like this:
MdlFileReader* fileReader = new MdlFileReader(file, m_settingsManager->getAesKey(), m_settingsManager->getAesInventoryKey()); fileReader->moveToThread(m_thread); connect(fileReader, &MdlFileReader::fileReaderDidFinish, this, [this](QVariant jsonObj) { m_thread->quit(); m_thread->wait(); if(!jsonObj.isNull()) { m_parser->updateFromJSONObject(jsonObj); } }); connect(m_thread, &QThread::started, fileReader, &MdlFileReader::startParseFile); m_thread->start();
in destructor of my main class I've added this line:
m_thread->deleteLater();
By the way how I can call slot from main thread if signal send from separate thread? Maybe problem is that I'm updating GUI in separate thread? Because in QML I have slot which uses Loader to load QML file. This slot called when file was parse and ready to use.
-
The connection should be queued, so the slot will be executed in the receiver thread (hence the use of signals and slots to transmit information for the GUI part to update)
I wonder if your object gets garbage collected
-
Thanks! But I've tried this and this didn't help me to solved problem :-(
About GC I'll check.
-
About the ownership: here is the doc
17/17