相关文章推荐
谈吐大方的小蝌蚪  ·  kubectl ...·  2 月前    · 
刚毅的围巾  ·  Collabra online not ...·  2 月前    · 
唠叨的石榴  ·  How do I use ...·  3 周前    · 
打酱油的书签  ·  Getting Started | ...·  1 年前    · 
胆小的领结  ·  iOS ...·  2 年前    · 
开心的斑马  ·  在sql ...·  2 年前    · 
爽快的手套  ·  FLINK SIDDHI ADDON ...·  2 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

QThread documentation suggests two ways to make code run in a separate thread. If I use moveToThread approach, I have to call processEvents() to issue the timeouts, to have the lambda executed. And this seems to cost a lot of CPU. Why is so?

class Worker : public QObject
    Q_OBJECT
    QTimer* timer;
    bool m_abort = false;
public:
    Worker() {}
    void abort() {m_abort = true;}
public slots:
    void run() {
        timer = new QTimer;
        connect(timer, &QTimer::timeout, []{qDebug() << "computed";});
        timer->start(1000);
        forever {
            if (m_abort) break;
            QCoreApplication::processEvents();
class MainWidget : public QWidget
    Q_OBJECT
    QThread thread;
    Worker* worker;
public:
    MainWidget()
        worker = new Worker;
        worker->moveToThread(&thread);
        connect(this, &MainWidget::start, worker, &Worker::run);
        thread.start();
        emit start();
    ~MainWidget(){worker->abort(); thread.quit(); thread.wait();}
signals:
    void start();

However if I subclass QThread and reimplement run() it's not necessary to call processEvents. And CPU cost seems lower. Why?

class Worker : public QThread
public:
    Worker() {}
protected:
    void run() override {
        QTimer timer;
        connect(&timer, &QTimer::timeout, []{qDebug() << "computed";});
        timer.start(1000);
        exec();
class MainWidget : public QWidget
    Q_OBJECT
    Worker* worker;
public:
    MainWidget()
        worker = new Worker;
        worker->start();
                IMHO it is almost always a bug to call processEvents(). There's usually always a better way. Same with having nested event loops (sometimes indirectly by using dialog boxes with .exec()). Those are all things that eventually lead to pain in Qt projects and should be avoided.
– Jesper Juhl
                Jan 7, 2020 at 16:08
                why do you need to use this timer and why you need forever loop for worker? You messed up something and I have no idea how to fix it since I do not see what exactly you are trying to achieve. Most probably you do not need threads at all. I'm suspecting XY problem so please provide more context. Please explain why do you think you need a multiple threads?
– Marek R
                Jan 7, 2020 at 16:27
                It superficially appears to me that your first solution is "busy waiting."  en.wikipedia.org/wiki/Busy_waiting ... Not what you want to do!
– Mike Robinson
                Jan 7, 2020 at 17:08
                I suggest checking the QtWS19 threading talk by Bo Thorsen! Maybe you will find a better solution to your problem.
– Andrea Ricchi
                Jan 8, 2020 at 10:50
                FYI, you should use at least std::atomic_bool instead of bool to manage your loop lifetime.
– Dmitry Sazonov
                Jan 8, 2020 at 15:37

your run() function 'blocks' the thread. It is being invoked in the thread context, but never returns. This means, the event loop in the thread doesn't get executed anymore as soon as your run() funtion is called.

For the timer events to call your lambdas, the event loop has to be processed. If you would modify your run function like this:

void run() {
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, []{qDebug() << "computed";});
    timer->start(1000);
    // don't loop here, instead exit the function 
    // and let the thread return back to the event loop

then your lambdas should get called. The thread will also keep running until you call thread.quit()

note: you can also connect directly to the '''started''' signal of the thread:

connect(&thread, &QThread::started, worker, &Worker::run);
thread.start();

moveToThread approach might be improved by calling run() function just after thread emit started.

But I still don't know why the way I put it initially doesn't work.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.