Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
658 views
in Technique[技术] by (71.8m points)

c++ - Why can't I start a QThread on a signal?

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...