Running QtConcurrent on member function resulting in error
-
Re: Creating a new thread with QtConcurrent did not work
I'll caveat this question with this: I am new to C++ (interpret pointers boggle my mind)
I am following the documentation for
QtConcurrent::run
here: https://doc.qt.io/qt-6/qtconcurrentrun.html#additional-api-featuresI am attempting to run the following code:
// This is a pointer to an Engine object from third party library LUI. auto engine = lui::QueryInterop<wise::Engine>(lui::GetLUI()); if (engine) { connect(&m_modelsLoadedWatcher, &QFutureWatcher<bool>::finished, this, &ConfigDialog::onNNModelsLoaded); // Begin loading models in new thread. m_modelsLoadedFuture = QtConcurrent::run(&wise::Engine::loadPytorchModelsAsync, engine); m_modelsLoadedWatcher.setFuture(m_modelsLoadedFuture); } else { // do some stuff. }
However, I am consistently getting the following error.
I figure something in the called member function must not be compatible. This is what it looks like:
void Engine::loadPytorchModelsAsync() { QString scriptModulesPath = QDir("plugins:").absolutePath() + QString("/wisePlugin/PyTorchModels/"); // spread out the processing of our heavy NN model loads over multiple threads auto pytorchLoadFunctions = wise::nn::GetPyTorchModelLoaders(scriptModulesPath); auto numberOfModelsToLoad = pytorchLoadFunctions.size(); auto progress = new QProgressDialog("Loading Neural Network Models...", "", 0, (int)pytorchLoadFunctions.size(), lui::GetLUI()->getUI()->mainWindow()->centralWidget()); progress->setCancelButton(nullptr); progress->setMinimumDuration(0); progress->setValue(0); // Define lambda function which will update progress bar when a model is loaded. wise::IEngine::SubTaskCompleteFunction actionOnComplete = [progress, numberOfModelsToLoad](int numComplete) { // invoke on the main thread QMetaObject::invokeMethod(qApp, [progress, numComplete] { progress->raise(); // bring the widget to the front of the app progress->setValue(numComplete); }); }; // Queue load functions QueueSimpleBlockingTaskGroup(pytorchLoadFunctions, wise::IEngine::eTaskBlockType::BlockAWorkerThread, actionOnComplete); }
I'm not sure where to go from here honestly. It seems that I am following the documentation perfectly but I know that can't be true or this would be working. Can someone show me what I need to correct?
-
I got it to work by making the QFuture member variable of the class that was handling the GUI stuff, then just accessing it from the class I was working on above.
if (engine) { // Engine has a QFuture<void> member for the models being loaded. We will watch it here. connect(&m_modelsLoadedWatcher, &QFutureWatcher<bool>::finished, this, &ConfigDialog::onNNModelsLoaded); // We know that the implementation of IEngine is Engine, so cast. m_modelsLoadedWatcher.setFuture(dynamic_cast<wise::Engine*>(engine)->m_modelsLoadedFuture); }
Im curious however about the invokeMethod you were talking about. I started a new thread asking about it, as I did try it out: https://forum.qt.io/topic/140834/how-to-combine-qtconcurrent-with-qmetaobject-invokemethod.
-
Hi and welcome to devnet,
To rule out the obvious, can you build the example successfully ?
On a side note: you code snippet does not match the error you show in the image.
-
Now that you mention it, I remember that I thought that there would some trouble with that. Nice catch !
-
@SGaist said in Running QtConcurrent on member function resulting in error:
Now that you mention it, I remember that I thought that there would some trouble with that. Nice catch !
Hah, a co-worker taught me how to use intellisense to filter out the 96 overrides of QtConcurrent::run to discover the error :D
I'm running into new problems now (widgets must be created in GUI thread)... I found this thread which you participated in here, and take its contents to imply that I am calling QtConcurrent::run from a thread that is not the GUI thread, so any widgets created by that call will make this error occur.
Unfortunately, I'm not sure which thread is the GUI thread, so I guess I just have to move the
run
call around into different cpp files until I find the right one?I feel out of my depth here. I normally write models in Python and someone else does all this C++ work for me. This is what I get for volunteering to learn something new :D
-
The correct way is to not do GUI access in a method called through QtConcurrent::run.
Emit a signal or use invokeMethod but no direct access.
-
I got it to work by making the QFuture member variable of the class that was handling the GUI stuff, then just accessing it from the class I was working on above.
if (engine) { // Engine has a QFuture<void> member for the models being loaded. We will watch it here. connect(&m_modelsLoadedWatcher, &QFutureWatcher<bool>::finished, this, &ConfigDialog::onNNModelsLoaded); // We know that the implementation of IEngine is Engine, so cast. m_modelsLoadedWatcher.setFuture(dynamic_cast<wise::Engine*>(engine)->m_modelsLoadedFuture); }
Im curious however about the invokeMethod you were talking about. I started a new thread asking about it, as I did try it out: https://forum.qt.io/topic/140834/how-to-combine-qtconcurrent-with-qmetaobject-invokemethod.