【Qt】QThreadを使ってQTimerを別スレッドで動かす

QThreadとmoveToThreadを使ってQTimerを別のスレッドで実行する方法です。

同スレッド上で重い処理を行う場合やSleepでの停止によるQTimerの実行周期ズレを回避します。

QTimerをmoveToThreadで別スレッド化

  QTimer timer_th_;
  QThread thread_timer_;

  connect(&timer_th_, &QTimer::timeout, this, &MainWindow::timerTimeOutTh, Qt::DirectConnection);
  timer_th_.setTimerType(Qt::PreciseTimer);
  timer_th_.setInterval(1000);
  timer_th_.start();
  // 別スレッド化
  timer_th_.moveToThread(&thread_timer_);
  thread_timer_.start();

4行目は、QTimerのtimer_th_がタイムアウトした時に呼ばれるSLOTを設定しています。

connectの5番目の引数には、必ず「Qt:DirectConnection」を設定しましょう。

5行目、6行目がタイマーの設定で、7行目でタイマーをスタートしています。

9行目で、「moveToThread」を使って、timer_th_をthread_timer_上に移動します。そして、10行目でthread_timerをスタート。

以上で、QTimerを別のスレッドで動かすことができる様になります。

QThreadを使ってQTimerを別スレッドで動かすサンプル

簡単なプログラムを作成して動作の確認をしてみます。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <windows.h>
#include <iostream>
#include <string>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(&timer_mw_, &QTimer::timeout, this, &MainWindow::timerTimeOutMw);
    timer_mw_.setTimerType(Qt::PreciseTimer);
    timer_mw_.setInterval(1000);
    timer_mw_.start();

    connect(&timer_th_, &QTimer::timeout, this, &MainWindow::timerTimeOutTh, Qt::DirectConnection);
    timer_th_.setTimerType(Qt::PreciseTimer);
    timer_th_.setInterval(1000);
    timer_th_.start();
    // 別スレッド化
    timer_th_.moveToThread(&thread_timer_);
    thread_timer_.start();
}

MainWindow::~MainWindow()
{
    timer_mw_.stop();
    timer_th_.stop();
    thread_timer_.terminate();

    delete ui;
}

void MainWindow::timerTimeOutTh()
{
    // スレッドIDを出力する
    std::cout << "timer_th_ timeout thread_id:" << GetCurrentThreadId() << std::endl;
}

void MainWindow::timerTimeOutMw()
{
    // スレッドIDを出力する
    std::cout << "timer_mw_ timeout thread_id:" << GetCurrentThreadId() << std::endl;
}


void MainWindow::on_pushButton_clicked()
{
    Sleep(2000);
}
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTimer>
#include <QThread>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public slots:
    void timerTimeOutTh();
    void timerTimeOutMw();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;

    QThread thread_timer_;
    QTimer timer_th_;
    QTimer timer_mw_;
};
#endif // MAINWINDOW_H

mainwindow.cppの13~16行目がメインスレッドで動作するQTimerの設定、18~21行目がthread_timer_上で動作するQTimerの設定になっています。

どちらも1000ms周期で、スレッドIDを出力する処理が実行されます。

また、画面にボタンを配置して、ボタンが押された場合は、Sleep(2000)を実行してメインスレッドを2000msストップします。

実行すると、以下の様な結果が出力されます。

timer_mw_ timeout thread_id:11360
timer_th_ timeout thread_id:13928
timer_mw_ timeout thread_id:11360
timer_th_ timeout thread_id:13928
timer_th_ timeout thread_id:13928
timer_th_ timeout thread_id:13928
timer_mw_ timeout thread_id:11360
timer_mw_ timeout thread_id:11360
timer_th_ timeout thread_id:13928

3行目、4行目付近でボタンを押してメインスレッドが停止しているので、thread_timer_上で動作しているtimer_th_だけが動き続けています。

QThreadとmoveToThreadを使用すると、このように別スレッドでQTimerを動作させることができます。

スポンサーリンク

  • この記事を書いた人

まさじぃ

ダメプログラマ歴17年です。 プログラミング関連の事や、 自分で使って良かったもの等の紹介をメインにやっています。

-プログラミング
-,