C++ 为什么可以';我不能在信号上启动QThread吗?

C++ 为什么可以';我不能在信号上启动QThread吗?,c++,multithreading,qt,signals-slots,qthread,C++,Multithreading,Qt,Signals Slots,Qthread,我想在另一个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(

我想在另一个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();
工人

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!";
}
工作


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

我试图用我自己的MCVE重现OPs问题(只是稍微短一点)

这是OP观察到的。那么,什么

  • worker1.qThread.start
    信号连接到
    worker2.start
    插槽
  • worker1
    已启动
  • worker2
    似乎没有启动
让我怀疑的是:
moveToThread()

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

我不确定的是:在
QThread
启动之前,这可能吗

为了验证这一点,我对
moveToThread()
进行了注释:

输出:

Qt版本:5.13.0
启动“工人1”
启动“工人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();
}

奖金问题:

那么,这是否意味着“QThread::start”作为信号接收器是无用的呢

不,不是。即使不存在具有该签名的现有信号(我知道),应用程序开发人员也可以自由地“发明”一个

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

使用Qt4信号时,
QThread::start
插槽可以直接连接到
QThread::start
信号。(此时,
QThread::start
中唯一一个参数的默认值生效。)

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

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

Qt版本:5.13.0
启动“工人1”
“工作线程1”与其线程关联,从现在开始。
“worker 2”与其线程关联,从现在开始。
现在,
Start“worker 2”
不再作为
worker1.Start()
直接调用
worker2.qThread.Start()
发出

因此,使用Qt4信号,OP的原始代码可能已经工作。
不是信号和插槽的不兼容(有人猜测)导致了这个问题,可能是上面描述的
moveToThread()
问题(以及)使它不能令人满意地工作。

我试图用我自己的MCVE重现OPs问题(只是稍微短一点)

这是OP观察到的。那么,什么

  • worker1.qThread.start
    信号连接到
    worker2.start
    插槽
  • worker1
    已启动
  • worker2
    似乎没有启动
让我怀疑的是:
moveToThread()

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

我不确定的是:在
QThread
启动之前,这可能吗

为了验证这一点,我对
moveToThread()
进行了注释:

输出:

Qt版本:5.13.0
启动“工人1”
启动“工人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();
}

奖金问题:

那么,这是否意味着“QThread::start”作为信号接收器是无用的呢

不,不是。即使不存在具有该签名的现有信号(我知道),应用程序开发人员也可以自由地“发明”一个

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

使用Qt4信号时,
QThread::start
插槽可以直接连接到
QThread::start
信号。(此时,
QThread::start
中唯一一个参数的默认值生效。)

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

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

Qt版本:5.13.0
启动“工人1”
“工作线程1”与其线程关联,从现在开始。
“worker 2”与其线程关联,从现在开始。
现在,
Start“worker 2”
不再作为
worker1.Start()
直接调用
worker2.qThread.Start()
发出

因此,使用Qt4信号,OP的原始代码可能已经工作。 问题的原因不是信号和插槽的不兼容(有人猜测),而是上面描述的
moveToThread()
问题(也有可能),它的工作不令人满意。

如果使用,当插槽的签名不匹配时,会出现编译时错误。因此,您不会在“应用程序输出”中看到它们,而是在“构建输出”中看到它们,甚至无法启动应用程序。这与运行前无法检测到不匹配插槽的旧Qt信号相反。因此,应尽可能首选Qt5信号
#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();
}
  QObject::connect(&worker1.qThread, SIGNAL(started()), &worker2.qThread, SLOT(start()));