Solved QThread - moveToThread: Cannot move objects with a parent
-
@Christian-Ehrlicher thank you, but I'm lost in this concept of
parent
here. Could you help me a little more?In my case, each
selectPlugin
is generated from thePlugin
class.
ThePlugin
class uses thePlugin_API
class to interface.Here is the
Plugin
class:#ifndef PLUGIN_H #define PLUGIN_H #include <iostream> #include <QObject> #include <QtPlugin> #include <QtCore/qglobal.h> #if defined(PLUGIN_LIBRARY) # define PLUGIN_EXPORT Q_DECL_EXPORT #else # define PLUGIN_EXPORT Q_DECL_IMPORT #endif #include "plugin_api.h" class PLUGIN_EXPORT Plugin: public Plugin_API { Q_OBJECT Q_PLUGIN_METADATA(IID "com.rotortest.plugin") Q_INTERFACES(Plugin_API) public: explicit Plugin(); ~Plugin() override; private: void process() override; }; #endif // PLUGIN_H
Here is the
Plugin_API
class (shared library interface):#ifndef PLUGIN_API_H #define PLUGIN_API_H #include <QObject> class Plugin_API : public QObject { Q_OBJECT private: public: Plugin_API() { } virtual ~Plugin_API() = default; void start() { // Some code ... } public slots: virtual void process() = 0; signals: void finished(); }; // Declare our interface: Q_DECLARE_INTERFACE(Plugin_API, "com.rotortest.plugin") #endif // PLUGIN_API_H
I need the
Plugin_API
always to interface the plugin with the main app.How can I fix it?
-
@Christian-Ehrlicher , I don't know why, but now my error message has change to:
QObject::moveToThread: Current thread (0x7fa149605d40) is not the object's thread (0x7fa14ae4f3b0). Cannot move to target thread (0x7fa1494d0bb0) You might be loading two sets of Qt binaries into the same process. Check that all plugins are compiled against the right Qt binaries. Export DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded. 18:27:58: The program has unexpectedly finished.
Any ideas?
-
@fem_dev said in QThread - moveToThread: Cannot move objects with a parent:
Any ideas?
I already gave you the answer - don't set a parent or unparent it.
-
@fem_dev said in QThread - moveToThread: Cannot move objects with a parent:
QObject::moveToThread: Current thread (0x7fa149605d40) is not the object's thread (0x7fa14ae4f3b0).
Error is pretty clear. If you already moved a plugin to a thread you can't pull it from the thread you put it in and push it into another.
moveToThread
is push only so only the thread that owns the object can move it to another one -
@Christian-Ehrlicher sorry...I'm not identifying the
parent
in this case.I have 3 elements in this code:
QThread
Plugin
ClassPlugin_API
Class (Interface)
I didn't set a parent in any of these 3 elements. You can see it in the code above.
So:
1- Who is theparent
and thechildren
here?
2- How can I "don't set a parent"?
3- How can I "unparent"? -
@VRonin Thank you, but I'm newer in the
QThread
...and my english is not so good.Could you please give me a simple example? May be a pseudo-code or a sequence that I need to do to fix it?
I appreciate your help and support.
-
@fem_dev said in QThread - moveToThread: Cannot move objects with a parent:
I didn't set a parent in any of these 3 elements. You can see it in the code above.
Actually the code above is pretty lacking in this sense. we have no information regarding how you fill
_pluginStack
.How can I "unparent"?
call
_pluginStack[step_id]->setParent(nullptr);
@fem_dev said in QThread - moveToThread: Cannot move objects with a parent:
Could you please give me a simple example? May be a pseudo-code or a sequence that I need to do to fix it?
It's not clear what you are trying to do here. seems like you are creating a dedicated thread for each plugin but then you try to move those plugins in other threads, hard to give you an example if we don't know what you want to do. In this recent thread there are some examples of working with threads but I'm not 100% sure it applies to your case
-
@VRonin I will try to explain better...
Here is how I load each plugin using
QPluginLoader
where the input argument calledplugins
is a list ofshared libraries
absolute path.void job_manager::load_plugins(const QStringList plugins) { foreach(QString file, plugins) { QPluginLoader loader(file); if (loader.load()) { qInfo() << "Loaded: " << loader.fileName(); Plugin_API* plugin = qobject_cast<Plugin_API*>(loader.instance()); if (plugin) { // Store plugin in a QMap<std::string, Plugin_API*> _pluginsMap[plugin->getName()] = plugin; } else { qCritical() << "Wrong Plugin API! Could not cast: " << loader.fileName(); } } else { qCritical() << "ERROR: " << loader.fileName() << " - Msg: " << loader.errorString(); } } }
In the UI, I have a button called "run". Here is the
onClick()
action:void job_manager::on_run_btn_clicked() { // ===== Fill the plugin stack vector ===== // _numSteps = ui->added_list->count(); // UI execution plugin list. Each plugin is added by the user _pluginStack.reserve(_numSteps); // std::vector<Plugin_API*> for (size_t s = 0; s < _numSteps; s++) { // Get the plugin name: const std::string pluginName = ui->added_list->item(s)->text().toStdString(); // Store the plugin in a vector. // I do that because the user can run the same plugin multiple times in a user defined execution sequence. // Always in the serial order _pluginStack[s] = _pluginsMap[pluginName]; } callNextPlugin(); }
So, my
_pluginMap
can be something like:--------------------- | ["A"] => Plugin A | | ["B"] => Plugin B | ---------------------
And, my
_pluginStack
vector can be something like:| 0 | Plugin A | | 1 | Plugin A | | 2 | Plugin B | | 3 | Plugin A |
As you can see above, inside the
job_manager::on_run_btn_clicked()
method, I call thecallNextPlugin()
.void job_manager::callNextPlugin(void) { if (_currentStep + 1 > _numSteps) { // _current_step start from 0 std::cout << "Finished: All done!" << std::endl; return; } else { runPlugin(_currentStep); _currentStep++; } }
And here is the final
runPlugin()
method:void job_manager::runPlugin(const size_t step_id) { const auto& selectedPlugin = _pluginStack[step_id]; QThread* thread = new QThread; selectedPlugin->moveToThread(thread); // Runs Ok for the first time, but I got a error in the second time. connect(selectedPlugin, &Plugin_API::sendMsg, this, &job_manager::pluginMessage); connect(selectedPlugin, &Plugin_API::finished, thread, &QThread::quit); connect(selectedPlugin, &Plugin_API::finished, selectedPlugin, &Plugin_API::deleteLater); connect(selectedPlugin, &Plugin_API::finished, this, &job_manager::callNextPlugin); connect(thread, &QThread::started, selectedPlugin, &Plugin_API::start); connect(thread, &QThread::finished, thread, &QThread::deleteLater); thread->start(QThread::NormalPriority); }
So, when one plugin finish your job, the
job_manager
receives a signal&Plugin_API::finished
and it calls thecallNextPlugin()
method.I added the
_pluginStack[step_id]->setParent(nullptr);
right after themoveToThread()
line, but I got the same run-time error.QObject::moveToThread: Current thread (0x7fdf56f056e0) is not the object's thread (0x7fdf56e39c80). Cannot move to target thread (0x7fdf582ba950) You might be loading two sets of Qt binaries into the same process. Check that all plugins are compiled against the right Qt binaries. Export DYLD_PRINT_LIBRARIES=1 and check that only one set of binaries are being loaded.
Please, could you help me a little bit more? How can I fix it?
-
I added the _pluginStack[step_id]->setParent(nullptr); right after the moveToThread() line, but I got the same run-time error.
It should be added before
This running through workers is exactly the case described in the topic linked above, have a look at the last 2 examples to avoid unecessary operations
QObject::moveToThread: Current thread (0x7fdf56f056e0) is not the object's thread (0x7fdf56e39c80).
This error is saying that you called
moveToThread
on that plugin already. The main thread (0x7fdf56f056e0) sent the object to a secondary thread (0x7fdf56e39c80) already so it can't send it to 0x7fdf582ba950. only 0x7fdf56e39c80 can send the object to 0x7fdf582ba950 -
@VRonin I tried to put the
_pluginStack[step_id]->setParent(nullptr);
before themoveToThread()
too, but i got the same error message.I will try to look better the topic that you send to me.
If I have doubts, I will come back here, ok?
-
@fem_dev
Hi,
how our colleagues have already said a object has a parent which lives in the current thread so it cannot be moved!I don’t understand why you wrote:
const auto& selectedPlugin = _pluginStack[step_id];instead of
auto& selectedPlugin = _pluginStack[step_id];I'm wondering why the first instance runs well and then fail, or it seems so.
What difference are there? If I'd be you I'd try to find the differences between two plugins creation. -
if we want to be picky then
connect(selectedPlugin, &Plugin_API::finished, selectedPlugin, &Plugin_API::deleteLater);
will cause_pluginsMap
to contain dangling pointers (unless it's aQMap<QString, QPointer<Plugin_API> >
then it's just null pointers) -
@CP71 There's no difference. You are right.
-
@VRonin Yes...I think that this is my problem. Thank you!