Должен ли я вызывать processEvents () в потоке? - PullRequest
0 голосов
/ 07 января 2020
Документация

QThread предлагает два способа заставить код выполняться в отдельном потоке. Если я использую moveToThread подход, я должен позвонить processEvents(), чтобы выдать тайм-ауты, чтобы выполнить лямбду. И это, кажется, стоит много ресурсов процессора. Почему так?

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

Однако, если я подкласс QThread и переопределение run (), нет необходимости вызывать processEvents. И стоимость процессора кажется ниже. Почему?

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

Ответы [ 2 ]

2 голосов
/ 09 января 2020

ваша функция run () блокирует поток. Он вызывается в контексте потока, но никогда не возвращается. Это означает, что событие l oop в потоке больше не выполняется, как только вызывается ваша функция run ().

Для событий таймера, вызывающих ваши лямбды, событие l oop должен быть обработан. Если бы вы изменили свою функцию запуска следующим образом:

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
}

, тогда должны быть вызваны ваши лямбды. Поток также будет продолжать работать до тех пор, пока вы не вызовете thread.quit()

Примечание: вы также можете напрямую подключиться к сигналу '' '' запущен '' 'потока:

connect(&thread, &QThread::started, worker, &Worker::run);
thread.start();
0 голосов
/ 09 января 2020

Подход moveToThread может быть улучшен путем вызова функции run () сразу после запуска потокового выделения.

Но я до сих пор не знаю, почему первоначальный метод не работает.

...