Qt Event Loop
Table of Contents
1. Qt Event Loop
1.1. Overview
1.1.1. QThread
class MyThread : public QThread { public: void run() { qDebug() << "my thread run: " << currentThreadId(); exec(); } };
- myThread 需要在 run 里执行 exec 才能进入 event loop
- thread 默认的实现是 void run() {exec();}, 所以 QThread 默认会进入 event loop
1.1.2. QObject::moveToThread
SimpleObject obj; obj.moveToThread(&myThread); SimpleObject obj2(&obj); obj2.moveToThread(&thread);
- moveToThread 可以把 qobject 与 thread 绑定, obj 对应的 slot 会通过 event 的形式在相应的 thread 执行
- obj2 的 move 会失败, 因为整个 qobject 树的 object 必须在绑定到同一个 thread, 因为涉及到 object 释放的问题
1.1.3. Timer
QTimer timer; QObject::connect(&timer, &QTimer::timeout, &obj, &SimpleObject::handleEvent); timer.start(1000);
Timer 是通过直接向 thread event loop 注册 timer 实现的, 并不需要单独的线程
1.1.4. QCoreApplication::processEvents
QTimer timer2; timer2.setSingleShot(true); timer2.callOnTimeout(&obj, &SimpleObject::handleLongEvent); timer2.start(2000);
class SimpleObject : public QObject { Q_OBJECT void handleLongEvent() { while (true) { qDebug() << "handle long time event"; QCoreApplication::processEvents(); QThread::sleep(5); } } };
handleLongEvent 会长时间运行以致阻塞主线程的 event loop, 所以 handleLongEvent 中需要通过 QCoreApplication::processEvents 来强行处理event
1.1.5. QCoreApplication::postEvent
QCoreApplication::postEvent(&obj, new QEvent(QEvent::None));
class SimpleObject : public QObject { Q_OBJECT bool event(QEvent *event) { qDebug() << "got event" << event->type(); return QObject::event(event); } };
postEvent 可以向 event loop 直接发送一个特定的 event, QObject::event() 负责处理 event
1.1.6. QEventLoop
QCoreApplication::exec 和 QThread::exec 最终都是通过 QEventLoop::exec 进行 event loop 的
1.2. Event vs. Signal
- 若 connect 使用了 Qt::DirectConnection 参数, 则 slot 是直接调用 metacall 实现的
- 若 connect 使用了 Qt::QueuedConnection 参数, 则 slot 是通过 post 一个 event, 由 event loop 来调用 metacall 实现的.
- 若 connect 使用了 Qt::AutoConnection 参数, 则 qt 自己选择使用 DirectConnection 还是 QueuedConnection, 具体的, 若 sender 和 receiver 在同一个线程, 则使用 DirectConnection, 否则使用 QueuedConnection
1.3. exec
QCoreApplication::exec eventLoop.exec() while (!d->exit.loadAcquire()): processEvents(flags | WaitForMoreEvents | EventLoopExec); data->eventDispatcher.loadRelaxed()->processEvents(flags); EventDispatcher::processEvents : QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData); // postEventList !! while (i < data->postEventList.size()): const QPostEvent &pe = data->postEventList.at(i); ++i; QEvent *e = pe.event; QObject * r = pe.receiver; QCoreApplication::sendEvent(r, e); notifyInternal2(receiver, event); doNotify(receiver,event) notify_helper(receiver, event) if (sendThroughObjectEventFilters(receiver, event)): filtered = true; return filtered; // deliver the event consumed = receiver->event(event); d->pollfds.append(d->threadPipe.prepare()); switch (qt_safe_poll(d->pollfds.data(), d->pollfds.size(), tm)):
1.4. postEvent
QCoreApplication::postEvent // postEventList !! data->postEventList.addEvent(QPostEvent(receiver, event, priority)); dispatcher->wakeUp(); eventfd_write(fds[0], value)
1.5. sendEvent
sendEvent 会直接调用到对方的 event(), 是需要经过 event loop.
bool QCoreApplication::sendEvent(QObject *receiver, QEvent *event) notifyInternal2(receiver, event); // ... consumed = receiver->event(event);