为什么我不能在信号上启动 QThread?
Why can't I start a QThread on a signal?
我想在另一个 QThread 启动时启动一个 QThread,但它不起作用。
main.cpp 片段
Worker stat_worker;
stat_worker.moveToThread(stat_worker.stat_thread);
Worker some;
some.moveToThread(some.somethread);
QObject::connect(stat_worker.stat_thread, SIGNAL(started()), some.somethread, SLOT(start()));
QObject::connect(some.somethread, SIGNAL(started()), &some, SLOT(print_some()));
stat_worker.stat_thread->start();
worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker();
QThread *stat_thread = new QThread;
QThread *somethread = new QThread;
signals:
//some signals
void start_thread();
public slots:
//some slots
void print_some();
void somethread_starter();
};
#endif // WORKER_H
worker.cpp相关函数
void Worker::print_some()
{
qInfo() << "-somethread started() signal arrived!";
}
当我尝试通过单击按钮启动线程时,它也不起作用。
甚至创建一个启动线程的槽:
QObject::connect(stat_worker.stat_thread, &QThread::started, &some, &Worker::somethread_starter);
void Worker::somethread_starter()
{
qInfo() << "-I got started by another thread!";
somethread->start();
}
或启动另一个线程时发出的信号:
void Worker::wip_status(){
emit start_thread();
}
QObject::connect(stat_worker.stat_thread, &QThread::started, &stat_worker, &Worker::wip_status);
QObject::connect(&stat_worker, &Worker::start_thread, &some, &Worker::somethread_starter);
工作。
提前感谢您回复我的post。
我尝试用我自己的 MCVE(只是短了一点)重现 OPs 问题。
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
输出:
Qt Version: 5.13.0
Start "worker 1"
这是 OP 观察到的。那么,什么?
worker1.qThread.started
信号连接到 worker2.start
插槽
worker1
已启动
worker2
好像没有启动。
是什么让我产生了怀疑:moveToThread()
。
目的是将 Worker
对象与其成员 QThread
相关联。
我不确定的是:在 QThread
开始之前这可能吗?
为了检查这一点,我评论了 moveToThread()
:
Worker(const QString &name): name(name)
{
//moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
输出:
Qt Version: 5.13.0
Start "worker 1"
Start "worker 2"
我评论moveToThread()
的原因:
qThread::start()
的调用应该发生在主应用程序(线程)的上下文中。
所以,将 worker2
移动到它的 QThread
意味着信号被发送到 worker2.qThread
的事件循环——实际上还没有开始。
因此,无法处理该事件。
moveToThread()
应该稍后完成 – 例如响应 started()
信号:
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
connect(&qThread, &QThread::started, this, &Worker::moveThisToThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void moveThisToThread()
{
moveToThread(&qThread);
qDebug() << name << "associated to its thread, from now.";
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
输出:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
Start "worker 2"
"worker 2" associated to its thread, from now.
加分题:
So does that mean "QThread::start" is useless as receiver of a signal?
不,不是。即使没有具有该签名的现有信号(我知道),应用程序开发人员也可以自由地“发明”一个。
但是,请记住 Qt5 实际上并不需要明确标记 SLOT
s 才能将它们用于信号,过去可能会找到更明显的答案:
对于 Qt4 信号,QThread::start
插槽可以直接连接到 QThread::started
信号。 (QThread::start
中唯一一个参数默认值生效。)
由于我没有使用 Qt4 信号的经验(我从 Qt5 开始),我修改了我的示例代码以证明我是正确的:
QObject::connect(&worker1.qThread, SIGNAL(started()), &worker2.qThread, SLOT(start()));
输出:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
"worker 2" associated to its thread, from now.
Start "worker 2"
不再发出,因为 worker1.started()
现在直接调用 worker2.qThread.start()
。
因此,对于 Qt4 信号,OP 的原始代码可能已经生效。
不是信号和插槽的不兼容(正如有人猜测的那样)导致了这个问题,但可能是上面描述的 moveToThread()
问题(以及)并没有使它令人满意地工作。
我想在另一个 QThread 启动时启动一个 QThread,但它不起作用。
main.cpp 片段
Worker stat_worker;
stat_worker.moveToThread(stat_worker.stat_thread);
Worker some;
some.moveToThread(some.somethread);
QObject::connect(stat_worker.stat_thread, SIGNAL(started()), some.somethread, SLOT(start()));
QObject::connect(some.somethread, SIGNAL(started()), &some, SLOT(print_some()));
stat_worker.stat_thread->start();
worker.h
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker();
QThread *stat_thread = new QThread;
QThread *somethread = new QThread;
signals:
//some signals
void start_thread();
public slots:
//some slots
void print_some();
void somethread_starter();
};
#endif // WORKER_H
worker.cpp相关函数
void Worker::print_some()
{
qInfo() << "-somethread started() signal arrived!";
}
当我尝试通过单击按钮启动线程时,它也不起作用。
甚至创建一个启动线程的槽:
QObject::connect(stat_worker.stat_thread, &QThread::started, &some, &Worker::somethread_starter);
void Worker::somethread_starter()
{
qInfo() << "-I got started by another thread!";
somethread->start();
}
或启动另一个线程时发出的信号:
void Worker::wip_status(){
emit start_thread();
}
QObject::connect(stat_worker.stat_thread, &QThread::started, &stat_worker, &Worker::wip_status);
QObject::connect(&stat_worker, &Worker::start_thread, &some, &Worker::somethread_starter);
工作。
提前感谢您回复我的post。
我尝试用我自己的 MCVE(只是短了一点)重现 OPs 问题。
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
输出:
Qt Version: 5.13.0
Start "worker 1"
这是 OP 观察到的。那么,什么?
worker1.qThread.started
信号连接到worker2.start
插槽worker1
已启动worker2
好像没有启动。
是什么让我产生了怀疑:moveToThread()
。
目的是将 Worker
对象与其成员 QThread
相关联。
我不确定的是:在 QThread
开始之前这可能吗?
为了检查这一点,我评论了 moveToThread()
:
Worker(const QString &name): name(name)
{
//moveToThread(&qThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
输出:
Qt Version: 5.13.0
Start "worker 1"
Start "worker 2"
我评论moveToThread()
的原因:
qThread::start()
的调用应该发生在主应用程序(线程)的上下文中。
所以,将 worker2
移动到它的 QThread
意味着信号被发送到 worker2.qThread
的事件循环——实际上还没有开始。
因此,无法处理该事件。
moveToThread()
应该稍后完成 – 例如响应 started()
信号:
#include <QtWidgets>
struct Worker: QObject {
QString name;
QThread qThread;
Worker(const QString &name): name(name)
{
connect(&qThread, &QThread::started, this, &Worker::moveThisToThread);
connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
}
void start()
{
qDebug() << "Start" << name;
qThread.start();
}
void moveThisToThread()
{
moveToThread(&qThread);
qDebug() << name << "associated to its thread, from now.";
}
void reportFinished()
{
qDebug() << "Exit" << name;
}
};
// main application
int main(int argc, char **argv)
{
qDebug() << "Qt Version:" << QT_VERSION_STR;
QCoreApplication app(argc, argv);
Worker worker1("worker 1");
Worker worker2("worker 2");
// install signal handlers
QObject::connect(&worker1.qThread, &QThread::started, &worker2, &Worker::start);
worker1.start();
// runtime loop
return app.exec();
}
输出:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
Start "worker 2"
"worker 2" associated to its thread, from now.
加分题:
So does that mean "QThread::start" is useless as receiver of a signal?
不,不是。即使没有具有该签名的现有信号(我知道),应用程序开发人员也可以自由地“发明”一个。
但是,请记住 Qt5 实际上并不需要明确标记 SLOT
s 才能将它们用于信号,过去可能会找到更明显的答案:
对于 Qt4 信号,QThread::start
插槽可以直接连接到 QThread::started
信号。 (QThread::start
中唯一一个参数默认值生效。)
由于我没有使用 Qt4 信号的经验(我从 Qt5 开始),我修改了我的示例代码以证明我是正确的:
QObject::connect(&worker1.qThread, SIGNAL(started()), &worker2.qThread, SLOT(start()));
输出:
Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
"worker 2" associated to its thread, from now.
Start "worker 2"
不再发出,因为 worker1.started()
现在直接调用 worker2.qThread.start()
。
因此,对于 Qt4 信号,OP 的原始代码可能已经生效。
不是信号和插槽的不兼容(正如有人猜测的那样)导致了这个问题,但可能是上面描述的 moveToThread()
问题(以及)并没有使它令人满意地工作。