5

I am developing an application with Qt whereby I want to update my GUI from another unrelated class with functions executing in a different thread.

I registered a callback function from the Qt GUI class to the other class using standard C++ constructs std::function and std::bind.

On trying to execute the GUI callback function from the other class, my program crashes with "qt cannot send events to objects owned by a different thread".

My questions are, what is happening here exactly. Why is it not permissive to communicate between two threads like this. Is it possible to resolve this in some way , or does Qt just not allow other unrelated functions to update the GUI in this way ?

For information , I am using portaudio libraries on windows. It executes a callback in a different thread. When I receive audio, I try to update my GUI.

Thank you in advance

Engineer999
  • 3,683
  • 6
  • 33
  • 71
  • [Possible](https://stackoverflow.com/questions/638251/how-to-emit-cross-thread-signal-in-qt) [dupes](https://stackoverflow.com/questions/2086142/qt-signaling-across-threads-one-is-gui-thread) but they are rather old. [This one](https://stackoverflow.com/questions/40382820/how-to-leverage-qt-to-make-a-qobject-method-thread-safe) doesn't quite fit the question but is modern and should answer the question. – nwp Jun 02 '17 at 12:48
  • You might try asking the same question about Java Swing. The inventors of Java first created a multi-threaded windowing toolkit called AWT, but making it work right turned out to be a much harder problem than they expected. Eventually, they gave up on AWT, and created a new, single-threaded toolkit called Swing. Their reasons for making Swing single threaded probably are valid for any window toolkit in any language. I don't remember where I read about it, but you probably can find it using Google. – Solomon Slow Jun 02 '17 at 12:51
  • Thanks. I'm thinking the cleanest way for me possibly is to start a QThread running on my GUI when I push a button or whatever. The QThread will then poll flags of my other class and update the GUI accordingly. I normally don't like polling, but do you think this is my best (or only) option? – Engineer999 Jun 02 '17 at 12:55
  • 1
    Sounds like precisely the scenario for `Qt` [queued signal/slot connections](http://doc.qt.io/qt-5/threads-qobject.html). – G.M. Jun 02 '17 at 13:30
  • Your difficulty seems to stem from HOW you're connecting your GUI classes in the main thread to your non-Qt classes in the worker thread. Could you post that portion of code, please? – RobbieE Jun 04 '17 at 07:48

1 Answers1

6

You're probably being thrown off by the "send events" phrase. In Qt, this phrase has a strict technical meaning. Namely:

  • to send events means to use QCoreApplication::sendEvent, which then immediately invokes QObject::event on the receiver. It is an error to send events when the sending and receiving threads are different.

  • to post events means to use QCoreApplication::postEvent, which posts the event to the receiving object thread's event queue. The QObject::event on the receiver is invoked later by the receiver thread's event loop.

When objects live in different threads, you're not allowed to send events, only to post them. This points to the underlying cause of your issue/

Any method you access on a QWidget or a derived class must be accessed on its thread(), i.e. the main thread. Everything inside of QWidget can use sendEvent freely as the sending thread and receiving object's thread are identical by contract. By calling QWidget methods from the wrong thread, you break that contract by indirectly using sendEvent and thus fail.

Only methods that you yourself have implemented and are thread-safe can be called from other threads - and they can't use sendEvent.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313