Unexpected behaviour in slot with Qt::DirectConnection



    1. 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 );
      }@

    2. It is connected in MainWindow class like this:
      @bool plugin_connected = connect( plugin, SIGNAL(SigSlotSelector( QObject* )),
      this, SLOT(SigSlotSelector( QObject* )));@

    3. 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

    }@

    1. 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.



  • Are you yourself moving the plugin to a different thread or is automatically done by Qt?



  • 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.



  • No it must not.

    A plugin does not necessarily live in a different thread. Actually most of them do not. I don't know why your's is, but that usually is a deliberate decision made by the plugin developer or the developer using the plugin.



  • 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.



  • bq. where do you use QPluginLoader ?

    In MainWindow constructor. I will not provide all the code, it is proprietary, LGPLed.



  • So, if you can't provide a (simplified, reduced) example, where it happened, it's up to you to find the reason of the problem, sorry. I didn't want to read you full source code, the best is to reduce it to a minimum.



  • Sorry... But I have no much free time now to create branch with all significant code. Just imagine how it would be:

    1. main application loads plugin which exports slots in special structure
    2. main application loads another plugin which exports signals in special structure
    3. main application connects signals from 2nd plugin to slots in 1st, but one of senders is QThread object in 2nd plugin
    4. main application shows it's window and enters to it's main loop, it has a button which starts some method from 2nd plugin
    5. 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.


  • Moderators

    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.



  • Probably you ever did not following:

    • one of plugins is multithreaded
    • in second thread it communicates to another plugin in some manner

  • Moderators

    We do use threading in Qt Creator quite heavily in places. We do also use Direct Connections - even in threads.

    Maybe we are just doing it right;-)

    Seriously: The plugin loader does not "turn on multithreading". It is just a nice wrapper around dlopen which loads a piece of code into the address space of your application. It does not care what that code does at all.



  • bq. Maybe we are just doing it right

    May be. Then just write to documentation how it must be done right. Or Qt still sometimes can work unexpectedly ;-) to it's creators...

    I already shown pieces of code which do plugin loading. What is wrong there?
    The thread is just like this:

    @DThread::DThread(MainWindow *parent) : QThread(parent)@

    It was developed long time ago and works fine.

    @We do also use Direct Connections – even in threads.@

    Direct Connections in threads work fine for me except with QtGui - as signed in docs.


  • Moderators

    I am not a lawyer, but the LGPL is not considered to be a proprietary license. You need to pass the your source code on to your customers according to the LGPL. Of course we here are not your customers, so there is no obligation to show it to us:-)

    Actually the LGPL does not really make much sense for applications at all I think. You might want to contact a lawyer before sending out your product to your customers.



  • I'm not an owner of this software. I'm developer. I cannot distribute code without owner's permission. Lets not discuss this here.



  • [quote author="Gourmand" date="1308574464"]bq. Maybe we are just doing it right

    May be. Then just write to documentation how it must be done right. Or Qt still sometimes can work unexpectedly ;-) to it's creators...[/quote]

    This documentation is out there. It just reads:

    You must not use direct connections in multi thread signal/slots connections. You do use threads and you do force direct connections. Don't blame Qt for the disaster!

    I'll leave it to you to find many more very good documentation on that topic in a prominent place on the DevNet homepage. Additionally there are many other places where all this stuff is mentioned - scan the docs for multi threading stuff, it even has an intro on that. Thousands of developers out there are doing it right - should be worth a thought.

    And no, it is not the responsibility of Qt or the doc team to write in every class if it could have unexpected side effects if used in a wild puzzle of application design that no one can foresee, including enforcing stuff that's forbidden.



  • The blame is not about direct connections. They work as expected. Automatic multithreading mode for all plugins connected through signals/slots to multithreading one was truly unexpected. This is not documented. If something goes as not expected and is not documented - this is a bug (documented bug is not a bug but is a feature). Anybody is free to reproduce my design in a manner that I described before. There was no any forbidden stuff enforced. Just legal.

    Lets finish this... Now all I created before work well with multithreading. I have some next questions about QWidget in plugin. Will opent another thread for this.


  • Moderators

    There is no "multithreading mode" for plugins.



  • Qt does a pretty good job on deciding if a signal is sent to a receiver in a thread living in another thread and thus falling back to a queued connections. Thousands of developers and applications out there rely on that.

    It is up to you to proof that your objects actually live in the same thread and Qt is assuming wrong.

    If you're not willing to contribute some sample code for your "proof", then you're on your own. No one here believes in what you claim.

    EDIT:
    Oh, and just to add: It has absolutely nothing to do with plugins. You would have the very same problem even if you linked the code of your two plugins statically to your application. Point.



  • I know for a fact that signal-slot connections between objects instantiated from different plugins behave just like any other connection. If not, than You Are Doing It Wrong(TM), unless you present compelling evidence to the contrary. However, since you won't share an example displaying your issue with us, it will be up to you to figure out what you do wrong exactly. Pointing at Qt is not going to help you. Good luck with that.

    Edit:
    Note that I don't claim that Qt is bug free. It is not. But this is not one of them.



  • There is no automatic multi-threading mode for plugins and so it cannot be documented. What you are seeing is the direct and predictable result of the code you designed and implemented. Whether this was a conscious decision or an unexpected/unanticipated behaviour on your part does not matter. This is not a bug in Qt (either documentation or source).

    If you are still convinced that this is a bug in Qt then you will need to spend the time to make small compilable example that reproduces the issue. With this then we or the trolls can help you in fixing it or explaining the code paths that lead to the observed behaviour.

    Doing the above is often a valuable process anyway since by doing so you very often find the bug or the key to understanding the issue.

    Nobody is trying to accuse you of not understanding signals/slots/connections or multi-threading. Just that sometimes when used in conjunction these topics can lead to what seems like strange behaviour. I have been there myself many times ;-)

    Good luck with the rest of your project.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.