3

I use Qt and I need to execute some code in the main thread. I realized that successfully using signals & slots.

My question is, even tho it's working atm: what defines in which thread a slot is executed as the direct result of signal emitting?

Is it inside the thread that executes the connect() function or what?

qwe
  • 766
  • 1
  • 5
  • 15

2 Answers2

5

It depends how you set up your connection.

  • If you use Qt::DirectConnection, the slot will be executed immediately in the signaling thread, bypassing any event loop.

  • If you use a Qt::QueuedConnection, it will be executed in the receiving objects event loop, in the receiving objects thread.

  • If you don't specify the connection type, it defaults to Qt::AutoConnection, which defaults to Qt::QueuedConnection if the two QObjects have different thread affinities.

Nicolas Holthaus
  • 7,763
  • 4
  • 42
  • 97
  • So I guess my question now is how the "recieving object's event loop" is specified? – qwe May 05 '16 at 17:50
  • 1
    it's the main thread unless you explicitely use `QObject::moveToThread()`, or are doing weird things with `std::thread` and lambda functions and creating your own event loops (which I prefer to `QThread`). – Nicolas Holthaus May 05 '16 at 17:51
  • Thanks! Last thing: can you please point me to a piece of Qt's documentation where it's explicitly mentioned that it's the main thread unless you move it? – qwe May 05 '16 at 17:54
  • 1
    you have to read between the lines bit, but check [Threads an QObjects](http://doc.qt.io/qt-4.8/threads-qobject.html), specifically the "per-thread event loop section". It says an objects affinity is for the thread in which it's created, which is the main thread, unless you create the object in some other thread. Creating outside of the main thread is not typical in Qt and actually pretty hard to do if you use `QThread`, so when in doubt you've almost certainly created your object in the main thread. GUI objects can _only_ live in the main thread, so those are obvious as well. – Nicolas Holthaus May 05 '16 at 17:57
  • @NicolasHolthaus "Creating outside of the main thread is not typical in Qt and actually pretty hard to do if you use QThread" Really? `QThread thread; thread.start(); QObject o; o.moveToThread(&thread); QTimer::singleShot(0, &o, []{ new QObject; });`: you get a new `QObject` constructed in `thread`. Easy-peasy. Or, see [this answer](http://stackoverflow.com/a/21653558/1329652) for other ways. – Kuba hasn't forgotten Monica May 06 '16 at 20:51
  • @NicolasHolthaus If you only care for a thread from the global pool, it's even easier: `QtConcurrent::run([]{ new QObject; });` The `QThread` is the first available thread from the pool. IOW, it's not only dead easy, it can be pretty much an all-the-time sort of an operation. All you need is one parent object that creates children, and at some point you move it to another thread: all the children get moved with it, all new children get created there. And so on. – Kuba hasn't forgotten Monica May 06 '16 at 20:55
  • 1
    @Kuba hard as in you won't do it by accident if you have no clue what you are doing. My understanding was the OP didn't know which thread he was creating objects in, and what I was trying to say was it would be hard not to put them in the main thread without knowing you did that. I meant "not typical" as in "not the default behavior". – Nicolas Holthaus May 06 '16 at 21:00
1

A directly connected slot always executes immediately, before the signal returns.

A slot connected via a queued connection will execute in the event loop running in its object's thread(). The slot is called from within the exec().

The default automatic connection determines which method to use every time the signal is emitted. If the target object is in the same thread, the slot will be called immediately from the signal, otherwise an event will be posted to the target object, picked up by the target thread's event loop, and executed there.

The logic is, effectively:

void mySignal(params) {
  // moc-generated code below
  for (all directly connected slots, all automatically connected slots in this thread):
    slot(params);
  for (all queued-connected slots):
    QCoreApplication::postEvent(slot's object, new QMetaCallEvent(slot, params));
}

The direct connection doesn't require an event loop to work, and is like any indirect function call through a function pointer.

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