QThread를 이용한 스레드 생성에는 몇가지 방법이 있다. 간단한 예제를 통해서 하나씩 알아본다.
worker-object를 QThread객체로 이동(move To Thread)하여 사용하는 방법
worker.h
#include <QObject>
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
virtual ~Worker();
public slots:
void doWork(const QString &);
signals:
void start(const QString &);
void resultReady(const QString &result);
};
worker.cpp
#include "worker.h"
Worker::Worker(QObject *parent) : QObject(parent)
{
}
Worker::~Worker()
{
qDebug() << Q_FUNC_INFO;
}
void Worker::doWork(const QString &meter) {
QString result("hello");
// 여기서 오래걸리는 작업을 수행
emit resultReady(result + parameter);
}
main.cpp
#include "worker.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread thread;
Worker *worker = new Worker;
worker->moveToThread(&thread);
thread.start();
QObject::connect(worker, &Worker::start, worker, &Worker::doWork);
QObject::connect(&thread, &QThread::finished, worker, &QObject::deleteLater);
QObject::connect(worker, &Worker::resultReady, [&](const QString &result){
qDebug() << result;
thread.quit(); // 스레드중지
});
emit worker->start("World");
return a.exec();
}
QThread를 서브클래싱하여 run() 함수를 다시 구현하는 방법
mythread.h
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
MyThread();
~MyThread() override;
protected:
void run() override;
};
mythread.cpp
#include <QDebug>
#include "mythread.h"
MyThread::MyThread()
{
}
MyThread::~MyThread()
{
qDebug() << Q_FUNC_INFO;
}
void MyThread::run()
{
forever{ // for(;;)와 동일. 무한 루프를 작성하는 데 편의를 제공하는 매크로.
// 여기서 오래걸리는 코드를 실행
// 스레드에서 실행 중인 작업을 중지해야 하는 경우 true가 반환됨. 중단은 requestInterruption() 함수로 요청할 수 있다.
if ( QThread::currentThread()->isInterruptionRequested() ) {
qDebug() << Q_FUNC_INFO << " terminated";
return;
}
}
}
main.cpp
#include "mythread.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread *thread = new MyThread;
QObject::connect(thread, &MyThread::finished, thread, &QObject::deleteLater);
// 스레드 시작
thread->start();
QTimer::singleShot(3000, &a, [thread](){
// 3초후에 스레드 중단을 요청.
thread->requestInterruption();
});
return a.exec();
}
create() 정적 메서드를 호출하는 방법
Qt 5.10부터는 create() 정적 메서드를 호출하여 스레드를 생성할 수 있다.
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
void f(){
forever{
// 여기서 오래걸리는 작업을 수행
if ( QThread::currentThread()->isInterruptionRequested() ) {
return;
}
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
auto thread = QThread::create(f); // 함수 f를 실행할 새로운 QThread 객체를 만든다.
thread->start(); // 스레드 시작
return a.exec();
}
QThread는 스레드가 시작될 때 started() 를, 중지될 때 finished() 신호를 통해 통지하고 isFinished() 및 isRunning()을 사용하여 스레드 상태를 알 수 있다.
스레드를 중지 할 때는 exit() 또는 quit()를 호출한다. 실행중인 스레드를 강제로 종료하는 terminate() 를 호출 할 수 있지만 그런 상황은 되도록이면 없어야한다.
exit() 또는 quit()를 호출한 다음에는 스레드가 실행을 완료 할 때까지 (또는 지정된 시간이 지날 때까지) wait()를 사용하여 호출 스레드를 차단하는 것이 좋다.
Qt 4.8부터는 finished() 신호를 QObject::deleteLater()에 연결하여 종료 한 스레드 객체를 안전하게 해제 할 수 있다.
또한 플랫폼 독립적인 정적 sleep 함수를 제공한다. sleep(), msleep() 및 usleep()은 각각 초, 밀리초 및 마이크로초를 단위의 함수들이다.
Qt는 이벤트 중심(event-driven) 프레임 워크이므로 일반적으로 wait() 및 sleep() 함수는 필요하지 않을 수 있다. wait() 대신 finished() 시그널을 이용하는 것을 고려하자.