为什么我不能在信号上启动QThread? [英] Why can't I start a QThread on a signal?

查看:41
本文介绍了为什么我不能在信号上启动QThread?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在另一个启动时启动一个QThread,但是它不起作用.

main.cpp代码段

  Worker stat_worker;stat_worker.moveToThread(stat_worker.stat_thread);工人一些;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:公共QObject{Q_OBJECT上市:显式Worker();QThread * stat_thread =新的QThread;QThread * somethread =新的QThread;信号://一些信号void start_thread();公共插槽://一些插槽void print_some();void somethread_starter();};#endif//WORKER_H 

worker.cpp相关功能

  void Worker :: print_some(){qInfo()<<"-somethreadstart()信号到达!";} 

当我尝试通过单击按钮启动线程时,也没有用.

甚至创建一个启动线程的插槽:

  QObject :: connect(stat_worker.stat_thread,& QThread :: started,& some,& Worker :: somethread_starter);无效的Worker :: somethread_starter(){qInfo()<<-我是从另一个线程开始的!"somethread-> start();} 

或在启动另一个线程时发出的信号:

  void工作者:: wip_status(){发出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); 

工作.

提前感谢您回复我的帖子.

解决方案

我尝试使用自己的MCVE(略短一些)重现OP问题.

  #include< QtWidgets>struct Worker:QObject {QString名称;QThread qThread;Worker(const QString& name):名称(名称){moveToThread(& qThread);connect(& qThread,& QThread :: finished,this,& Worker :: reportFinished);}无效的start(){qDebug()<<开始"<<名称;qThread.start();}void reportFinished(){qDebug()<<退出"<<名称;}};//主要应用int main(int argc,char ** argv){qDebug()<<"Qt版本:"<<QT_VERSION_STR;QCoreApplication应用程序(argc,argv);工人worker1(工人1");工人worker2(工人2");//安装信号处理程序QObject :: connect(& worker1.qThread,& QThread :: started,& worker2,& Worker :: start);worker1.start();//运行时循环返回app.exec();} 

输出:

  Qt版本:5.13.0开始"worker 1". 

这是OP观察到的.那又怎样呢?

  • worker1.qThread.started 信号连接到 worker2.start 插槽
  • worker1 已启动
  • worker2 似乎没有开始.

让我感到怀疑的是: moveToThread().

目的是将 Worker 对象与其成员 QThread 相关联.

我不确定的是:在 QThread 启动之前是否可能?

要检查这一点,我评论了 moveToThread():

  Worker(const QString& name):名称(名称){//moveToThread(& qThread);connect(& qThread,& QThread :: finished,this,& Worker :: reportFinished);} 

输出:

  Qt版本:5.13.0开始"worker 1".开始"worker 2" 

我评论 moveToThread()的原因: qThread :: start()的调用应在主应用程序(线程)的上下文中进行.因此,将 worker2 移至其 QThread 意味着信号已发送至 worker2.qThread 的事件循环–该循环实际上尚未启动.

因此,该事件无法处理.

moveToThread()应该稍后执行-例如响应 started()信号:

  #include< QtWidgets>struct Worker:QObject {QString名称;QThread qThread;Worker(const QString& name):名称(名称){connect(& qThread,& QThread :: started,this,& Worker :: moveThisToThread);connect(& qThread,& QThread :: finished,this,& Worker :: reportFinished);}无效的start(){qDebug()<<开始"<<名称;qThread.start();}void moveThisToThread(){moveToThread(& qThread);qDebug()<<名称<<从现在开始与其线程相关联.";}void reportFinished(){qDebug()<<退出"<<名称;}};//主要应用int main(int argc,char ** argv){qDebug()<<"Qt版本:"<<QT_VERSION_STR;QCoreApplication应用程序(argc,argv);工人worker1(工人1");工人worker2(工人2");//安装信号处理程序QObject :: connect(& worker1.qThread,& QThread :: started,& worker2,& Worker :: start);worker1.start();//运行时循环返回app.exec();} 

输出:

  Qt版本:5.13.0开始"worker 1".工人1"指的是工人1".从现在开始与其线程相关联.开始"worker 2"工人2"从现在开始与其线程相关联. 


奖励问题:

这是否意味着"QThread :: start"作为信号的接收器是没有用的吗?

不,不是.即使不存在带有该签名的信号(据我所知),应用程序开发人员也可以发明"一个信号.

但是,请记住,Qt5实际上并不需要显式标记的 SLOT 来将其用于信号,过去可能会找到更明显的答案:

使用Qt4信号,可以将 QThread :: start 插槽直接连接到 QThread :: started 信号.( QThread :: start 中唯一一个参数的默认值随后生效.)

由于我没有使用Qt4信号的经验(我从Qt5开始),因此我修改了示例代码以证明自己是正确的:

  QObject :: connect(& worker1.qThread,SIGNAL(started()),& worker2.qThread,SLOT(start())); 

输出:

  Qt版本:5.13.0开始"worker 1".工人1"指的是工人1".从现在开始与其线程相关联.工人2"从现在开始与其线程相关联. 

开始"worker 2" 不再发出,因为 worker1.started()调用 worker2.qThread.start()现在,直接.

因此,对于Qt4信号,OP的原始代码可能已工作.引起问题的不是信号和插槽的不兼容(有人猜到了),但上述 moveToThread()问题(也)并没有使它令人满意地工作.

I want to start a QThread when another one starts, but it doesn't work.

main.cpp snippet

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 related function

void Worker::print_some()
{
    qInfo() << "-somethread started() signal arrived!";
}

When I tried starting a thread with clicking a pushbutton it didn't work either.

Even creating a slot which starts the thread:

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();
}

or a signal that is emitted on starting the other thread:

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);

work.

Thanks in advance for replying to my post.

解决方案

I tried to reproduce OPs issue with my own MCVE (which is just a bit shorter).

#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();
}

Output:

Qt Version: 5.13.0
Start "worker 1"

This what OP observed. So, what?

  • the worker1.qThread.started signal is connected to the worker2.start slot
  • the worker1 is started
  • worker2 doesn't seem to start.

What made me suspicious: moveToThread().

The intention is to associate the Worker object with its member QThread.

What I'm not sure about: Is this possible before the QThread is started?

To check this out, I commented the moveToThread():

  Worker(const QString &name): name(name)
  {
    //moveToThread(&qThread);
    connect(&qThread, &QThread::finished, this, &Worker::reportFinished);
  }

Output:

Qt Version: 5.13.0
Start "worker 1"
Start "worker 2"

The reason why I commented the moveToThread(): The call of qThread::start() should happen in the context of the main application (thread). So, moving worker2 to its QThread means that the signal is sent to the event loop of worker2.qThread – which is actually not yet started.

Hence, the event cannot be processed.

The moveToThread() should be done later – e.g. in reaction of the started() signal:

#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();
}

Output:

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.


Bonus Question:

So does that mean "QThread::start" is useless as receiver of a signal?

No, it's not. Even if there is no existing signal with that signature (I know about) the application developer is free to "invent" one.

However, remembering that Qt5 doesn't actually require explicitly marked SLOTs to use them for signals, a more obvious answer may be found in the past:

With Qt4 signals, the QThread::start slot could have been connected to the QThread::started signal directly. (The default value of the one and only parameter in QThread::start becomes effective then.)

As I have no experience with Qt4 signals (I started with Qt5), I modified my sample code to prove me right:

  QObject::connect(&worker1.qThread, SIGNAL(started()), &worker2.qThread, SLOT(start()));

Output:

Qt Version: 5.13.0
Start "worker 1"
"worker 1" associated to its thread, from now.
"worker 2" associated to its thread, from now.

The Start "worker 2" isn't emitted anymore as worker1.started() calls worker2.qThread.start() directly, now.

So, with Qt4 signals the original code of OP might have been worked. It wasn't the incompatibility of signal and slot (as somebody guessed) which caused the issue but probably the above described moveToThread() issue (as well) which didn't make it work satisfyingly.

这篇关于为什么我不能在信号上启动QThread?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆