Unexpected behaviour in slot with Qt::DirectConnection
-
-
There is plugin (proper Qt plugin in separate DLL) with some signal emitted to slot in main application. Definition:
@signals:
void SigSlotSelector( QObject* );@
and implementation:
@void SomePlugin::operation()
{
emit SigSlotSelector( this );
}@ -
It is connected in MainWindow class like this:
@bool plugin_connected = connect( plugin, SIGNAL(SigSlotSelector( QObject* )),
this, SLOT(SigSlotSelector( QObject* )));@ -
And signal is accepted in MainWindow slot:
@private slots:
void SigSlotSelector( QObject* );@
implemented:
@void MainWindow::SigSlotSelector( QObject *parent )
{IOselector* selector = new IOselector( parent, this ); // ************ REMEMBER THIS LINE
}@
4. IOSelector is another class inside main app. It is declared:
@class IOselector : public QDialog {
Q_OBJECT
public:
IOselector( QObject*, MainWindow* );
~IOselector(){}
... and some methods and properties
}@
it's constructor looks like this:
@IOselector::IOselector( QObject* parent, MainWindow* _w )
: QDialog(), ui(new Ui::Dialog), _parent(parent), w(_w)
{
...
}@All this works fine. At least looks like works - signal is accepted by slot, then IOselector created, it shows Qdialog and so on. But slot is connected with Qt::AutoConnection that means it works asynchronously. For some purposes I needed synchronous call. I replaced connection with this:
@bool plugin_connected = connect( plugin, SIGNAL(SigSlotSelector( QObject* )),
this, SLOT(SigSlotSelector( QObject* )), Qt::DirectConnection);@
and got unexpected result. Signal connects, slot is being called. But on the line marked with ************ REMEMBER THIS LINE program crashes "in unusual way". I even cannot debug it.I just replaced
@IOselector* selector = new IOselector( parent, this );@
with
@QObject* selector = new QObject();@
this works. But
@QDialog* selector = new QDialog();@
crashes.Looks like that means - With Qt::DirectConnection it tries execute called slot in address space of plugin instead of main application. But this is impossible if application and plugin are dynamically linked. That means - slots with Qt::DirectConnection cannot be called from DLL-plugins. Probably with static plugins this will work. Is this described somewhere in Qt docs? I don't remember.
-
-
Interesting problem. I have never though about that (mainly because I never needed synchronous signal/slots over plugins). Do you still need to do it that way? If yes, then the best way would probably be to put IOSelector in an external library that you link to both your application and your plugin.
-
This does not work not with IOselector itself. Looks like problem appears when QtGui used in slot with DirectConnection. QtCore functions well.
Exactly I do not need synchronous connection mandatory. For while... But I'm not sure I'll not need it later. How "external library" will differ from QtGui4.dll? I tried link QtGui to plugin - I added QT += gui to it's .pro file and added private property QDialog* fakegui; which is initialized
@fakegui = new QDialog ();
delete fakegui;@
in plugin's startup method. This doesn't help. Plugin's DLL now depends from QtGui4.dll too but slot crashes anyway. Problem lays deeper...And of course I can use BlockingQueuedConnection
-
A-ha... the problem does not relates to plugin itself. It relates to GUI... Loaded plugin works not in main thread! But GUI can be used in main thread only or it can be linked to plugin and used inside it. A've got another plugin with it's own MainWindow and it works well.
I think some words about this should be added to Qt plugin docs.
-
This sounds really weird. It should work the way you designed it. Actually it's pretty just the same as the Qt Designer plugins work. As you speak of DLLs - there's one thing: check that your plugin and application uses the very same compiler settings as the Qt libs (mainly threaded/nonthreaded stdlib, debug/release settings). Windows is known for being very picky about this.
-
bq. Are you yourself moving the plugin to a different thread or is automatically done by Qt?
It was made automatically by Qt. I did nothing for that. Just downloaded plugin using
@QPluginLoader PluginLoader;
PluginLoader.setFileName( dir.absoluteFilePath( abspath ) );
QObject* plugin = qobject_cast<QObject*>( PluginLoader.instance() );@and later called it's start method:
@ .....
interface* plugin_interface = qobject_cast<interface*>( plugin );
if( plugin_interface )
{
SEGINTERFACES ifr = plugin_interface->start( this );
.....@bq. check that your plugin and application uses the very same compiler setting
I'm pretty sure they use all same settings. There is nothing about settings. In application console I see ASSERT error message about different threads.
Exactly Qt::BlockingQueuedConnection works well.
-
If the sender of your signal really is in another plugin, then you must use queued connections (automatic detections does the trick too). Direct connections will crash the application (but you know that already). You must not call GUI functions (including creating and/or showing a dialog) outside the main thread of a Qt application.
-
Now I see that. But this must be noticed in plugin docs. Exactly following: "Loaded plugin runs in different to main application thread, That means GUI functions from main application cannot be used from plugin not directly, nor from signal/slot pair with Qt::DirectConnection."
Now there is nothing about plugin threading in it's doc.
-
I AM of those plugins developer and main application developer... I made them all "by default" as recommended in Qt 4.7 docs and Max's Shlee book. By default plugin starts in different thread. If it should not - then there is Qt bug. If it should start in different thread by default - then I must be warned in docs about it. Now there is a hole about threading in plugins doc. Nothing.
-
A Qt plugin is simply a shared library with a root component object like stated here:
"http://doc.qt.nokia.com/4.7/qpluginloader.html":http://doc.qt.nokia.com/4.7/qpluginloader.html
So by default a Qt plugin does not live in another thread and also the QObjects that are created in the plugin do not live in another thread. That means connectinng signals and slots from Qt plugins with signals and slots from your application via direct connection is no problem and should work fine.
-
May be should. But does not. They run by default in separate threads. All plugins (now I created 3). Probably this is a bug in Qt.
I must tell - one of my plugins is exactly multi threaded. It has QThread object which runs inside this plugin to perform specific tasks. But it starts not always. All other code is single threaded. All settings are default.
-
Sorry, you are the only one reporting this. And with plugins working with a charm so very often, I seriously doubt that this is a bug in Qt.
And as you are introducing threads in at least one of the plugins, it is very likely that this causes the problems. Creating a well designed multithreaded application can be very tricky, just as debugging it.
I suspect some flow of control problem to cause the troubles, eg. by some object/method of a plugin which is meant to work single threaded being called from the second thread of another plugin, probably without you knowing or being intended by you.
-
Hi Gourmand,
If you really think, the problem is Qt located, you could post your code via some share hoster or gitorious (the best in simplified form). Then some people could have a look, whether it is really a Qt bug. But I don't think so. I already created plug-ins and it never was a problem.
so the interesting point would be, where do you use QPluginLoader ?
-
Exactly second thread in one of plugins calls another but not directly, via signal/slot, default connection. I expected this will not force other plugins start in separate threads. Docs say nothing about this. But I've got multithreaded plugins. Neverthless... I can work with multithreading too. I only want all these aspects be documented.
-
Sorry... But I have no much free time now to create branch with all significant code. Just imagine how it would be:
- main application loads plugin which exports slots in special structure
- main application loads another plugin which exports signals in special structure
- main application connects signals from 2nd plugin to slots in 1st, but one of senders is QThread object in 2nd plugin
- main application shows it's window and enters to it's main loop, it has a button which starts some method from 2nd plugin
- this method in 2nd plugin starts 2nd thread which sends signals - they are accepted by first plugin
This all requires some time to be created from scratch clearly and accurately. But I must do main job.
I think problem appeared by the following reason: one of loaded plugins IS multithreaded. PluginLoader does not know how it will later communicate between threads. It just turns on multithreading. I can check this - first plugin loaded is NOT multithreading for all plugins. I can look at how it communicates with main application. I expect it will work in single thread model. But after 2nd plugin loaded - then multithreading will be turned on. I'll try do that later, at free time.
If I'm right - this is not exactly a bug. This is just undocumented behavior.
-
We use lots of plugins in Qt Creator (actually everything but the plugin loader is a a plugin there) and so far never had any issues with connections between plugins. All plugins are in the same thread, too.