c++ - 为什么我不能在信号上启动QThread?

标签 c++ multithreading qt signals-slots 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
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);
工作。
在此先感谢您回复我的帖子。

最佳答案

我试图用自己的MCVE(只是短一点)重现OP的问题。

#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()信号的 react 中:
    #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来将它们用于信号,过去可能会找到一个更明显的答案:
    对于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()问题(也可能)并没有使它令人满意地工作。

    关于c++ - 为什么我不能在信号上启动QThread?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63067960/

    相关文章:

    c++ - 函数内联——有哪些损害性能的例子?

    c++ - 库/应用程序组合的 C++ 错误处理/错误日志记录

    c++ - QT:动态子按钮不可见

    java - 授予权限 java.lang.RuntimePermission 修改线程

    c++ - extern是否破坏封装

    项目中的 C++ 全局常量

    c++ - 使用哪种数据结构来查找元素

    c++ - 线程池共享资源锁定问题

    c# - File.Copy() 在多线程 C# 程序中复制损坏的文件

    c++ - Qt 子类化图形场景不允许我选择/聚焦到其上的图形项目