A QThread object manages one thread of control within the program. QThreads begin executing in run(). By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread. You can use worker objects by moving them to the thread using QObject::moveToThread().
The purpose of a QMutex is to protect an object, data structure or section of code so that only one thread can access it at a time (this is similar to the Java synchronized keyword). It is usually best to use a mutex with a QMutexLocker since this makes it easy to ensure that locking and unlocking are performed consistently.
아래의 소스는 Qt 프레임워크에서 Thread를 다루는 기본적인 예제이다. QMutex를 사용하여 Thread 동기화, Qt에서 Thread 사용을 위한 올바른 방법 그리고 UI(예, Label, Button 2개)에서 QThread를 사용하는 방법을 살펴본다.
기본예제(QMutex)
//main.cpp
#include "mythread.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyThread mThread1;
mThread1.Name = "T1";
MyThread mThread2;
mThread2.Name = "T2";
MyThread mThread3;
mThread3.Name = "T3";
mThread1.start();
mThread2.start();
mThread3.start();
mThread1.bStop = true;
mThread3.bStop = true;
return a.exec();
}
//mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QDebug>
#include <QMutex>
#include <QThread>
#pragma pack(1)
class MyThread : public QThread
{
public:
MyThread();
void run() override;
QString Name;
bool bStop;
QMutex mutex;
};
#pragma pack()
#endif // MYTHREAD_H
//mythread.cpp
#include "mythread.h"
MyThread::MyThread()
{
bStop = false;
}
void MyThread::run()
{
qDebug() << this->Name << " Running";
for (int i = 0; i < 10; i++) {
mutex.lock();
if (this->bStop) {
break;
}
mutex.unlock();
qDebug() << this->Name << " " << i;
QThread::msleep(10);
}
}
기본예제(Qt)
//main.cpp
#include "myobject.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QThread cThread;
MyObject cObject;
cObject.DoSetup(cThread);
cObject.moveToThread(&cThread);
cThread.start();
return a.exec();
}
//myobject.h
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QDebug>
#include <QObject>
#include <QThread>
class MyObject : public QObject
{
Q_OBJECT
public:
explicit MyObject(QObject *parent = nullptr);
void DoSetup(QThread &cThread);
public slots:
void DoWork();
};
#endif // MYOBJECT_H
//myobject.cpp
#include "myobject.h"
MyObject::MyObject(QObject *parent) : QObject(parent){}
void MyObject::DoSetup(QThread &cThread)
{
connect(&cThread, SIGNAL(started()), this, SLOT(DoWork()));
}
void MyObject::DoWork()
{
for (int i = 0; i < 10; i++) {
qDebug() << i;
QThread::msleep(100);
}
}
UI(Qt) 예제
//main.cpp
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
return a.exec();
}
//mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QDebug>
#include <QMutex>
#include <QThread>
#pragma pack(1)
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = nullptr);
void run() override;
bool bStop;
QMutex mutex;
signals:
void NumberChanged(int);
};
#pragma pack()
#endif // MYTHREAD_H
//mythread.cpp
#include "mythread.h"
MyThread::MyThread(QObject *parent) : QThread(parent){}
void MyThread::run()
{
for (int i = 0; i < 1000; i++) {
mutex.lock();
if (this->bStop) {
break;
}
mutex.unlock();
emit NumberChanged(i);
this->msleep(10);
}
}
//dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include "mythread.h"
#include <QCloseEvent>
#include <QDialog>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui
{
class Dialog;
}
QT_END_NAMESPACE
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog(QWidget *parent = nullptr);
~Dialog();
MyThread *mThread;
void closeEvent(QCloseEvent *event);
private:
Ui::Dialog *ui;
public slots:
void OnNumberChanged(int);
private slots:
void on_btnStart_clicked();
void on_btnStop_clicked();
};
#endif // DIALOG_H
//dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
mThread = new MyThread(this);
connect(mThread, SIGNAL(NumberChanged(int)), this, SLOT(OnNumberChanged(int)));
}
Dialog::~Dialog()
{
delete ui;
if (mThread->isRunning()) {
mThread->bStop = true;
mThread->terminate();
}
}
void Dialog::closeEvent(QCloseEvent *event)
{
event->ignore();
int result = QMessageBox::warning(this, "종료", "프로그램을 종료하시겠습니까?", QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
if (result == QMessageBox::Ok) {
event->accept();
}
}
void Dialog::OnNumberChanged(int cNumber)
{
ui->lblNumber->setText(QString::number(cNumber));
}
void Dialog::on_btnStart_clicked()
{
ui->btnStart->setEnabled(false);
ui->btnStop->setEnabled(true);
mThread->bStop = false;
mThread->start();
}
void Dialog::on_btnStop_clicked()
{
ui->btnStart->setEnabled(true);
ui->btnStop->setEnabled(false);
mThread->bStop = true;
mThread->terminate();
}