事件循环处理所有可用的事件:您的期望不正确。事件循环如何判断您想“暂停”某个事件?不能。
你真正想要的——但你是倒着写的——是让网络管理线程在 I/O 管理器完成初始化后启动。这样就不需要等待任何东西了!
在编写伪同步代码时会发生等待,这就是所有问题的根源。不要手动旋转事件循环。不要从QThread 继承(除了使其成为 RAII)。
最后,如果io_manager 和network_manager 都不需要特殊代码来处理它们在自己的线程中的事实,那就太好了。
首先,我们需要包含来自this answer 的函子调度代码。
// https://github.com/KubaO/stackoverflown/tree/master/questions/thread-sync-50188307
#include <QtCore>
namespace detail { template <typename F> struct FEvent : QEvent {
const QObject *const obj;
const QMetaObject *const type = obj->metaObject();
typename std::decay<F>::type fun;
template <typename Fun>
FEvent(const QObject *obj, Fun &&fun) :
QEvent(QEvent::None), obj(obj), fun(std::forward<Fun>(fun)) {}
~FEvent() { // ensure that the object is not being destructed
if (obj->metaObject()->inherits(type)) fun();
}
}; }
template <typename F> static void post(QObject *obj, F &&fun) {
Q_ASSERT(!qobject_cast<QThread*>(obj));
QCoreApplication::postEvent(obj, new detail::FEvent<F>(obj, std::forward<F>(fun)));
}
然后,我们需要一个真正的 RAII 线程,它总是可以安全地破坏:
class Thread final : public QThread {
Q_OBJECT
void run() override {
if (!eventDispatcher())
QThread::run();
}
public:
using QThread::QThread;
using QThread::exec;
~Thread() override {
requestInterruption();
quit();
wait();
}
template <typename F> void on_start(F &&fun) {
connect(this, &QThread::started, std::forward<F>(fun));
}
};
started 信号在线程内发出,任何传递给on_start 的函子都有效地注入到线程中。 run() 方法被重新实现为仅在之前未运行的情况下启动事件循环。这样我们就可以注入整个线程体来构造对象并旋转事件循环。
I/O 和网络管理器是简单的对象,而不是线程。我们将io_manager 和network_manager 的构造推迟到它们各自的线程。这样,各个对象就不必知道它们在哪个线程上运行。
#include <memory>
using app_logger = QObject;
using room_logger_manager = QObject;
class io_manager : public QObject {
Q_OBJECT
app_logger app_log{this};
room_logger_manager room_log_mgr{this};
public:
using QObject::QObject;
};
class network_manager : public QObject {
Q_OBJECT
public:
network_manager(QObject *parent = {}) : QObject(parent) {
do_something1();
do_something2();
}
void do_something1() { qDebug() << __FUNCTION__; }
void do_something2() { qDebug() << __FUNCTION__; qApp->quit(); }
};
int main(int argc, char *argv[]) {
QCoreApplication app{argc, argv};
QPointer<io_manager> iomgr; //optional
QPointer<network_manager> netmgr; //optional
Thread io_thread, network_thread;
io_thread.on_start([&]{
qDebug() << "I/O thread is running.";
io_manager mgr;
iomgr = &mgr;
network_thread.start();
io_thread.exec();
});
network_thread.on_start([&]{
qDebug() << "Network thread is running.";
network_manager mgr;
netmgr = &mgr;
network_thread.exec();
});
io_thread.start();
return app.exec(); // RAII all the way!
}
#include "main.moc"
输出:
I/O thread is running.
Network thread is running.
do_something1
do_something2
注意所有对象的生命周期是如何自动处理的。