Qt에서는 Project에 따라 pthread 및 QThread 등을 사용하여 Thread를 만들 수 있습니다.

간단한 예제를 바탕으로 pthread와 QThread의 사용법을 설명드리겠습니다.

먼저 각 Thread에 대한 정의를 알아본 후, pthread와 QThread를 사용한 간단한 프로그램 예제코드를 보도록 하겠습니다.


- pthread

pthread란 POSIX 스레드(POSIX Threads, 약어: PThread)는 병렬적으로 작동하는 소프트웨어의 작성을 위해서 제공되는 표준 API입니다.
Pthread는 모든 유닉스 계열 POSIX 시스템에서, 일반적으로 이용되는 라이브러리로 유닉스 계열 운영 체제라 하면 리눅스, 솔라리스 등이 포함됩니다. Unix 시스템뿐만 아니라 Windows 역시 여러가지 이유로 Pthread를 지원합니다.


pthread 예제 프로젝트는 main.cpp 하나의 파일로 구성되어 있는 형태입니다.
pthread id를 저장할 변수와 pthread에서 실행할 함수를 선언합니다.

pthread_t testthread;
void *ThreadFunction(void *arg);


thread의 attribute object를 선언하고 초기화 후, 동작해야할 조건을 설정하여 쓰레드를 생성하는 과정입니다.
선언된  pthread_attr_init(), pthread_attr_setdetachstate() 등의 함수 사용법 및 아규먼트 정보는 pthread_cancel 취소 요청하기 글 참고 부탁드립니다.

    int status = 0;
    int arg = 0;

    pthread_attr_t attr; // thread attribute object
    pthread_attr_init(&attr); // initialize
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); // thread state option

    if (pthread_create(&testthread, &attr, ThreadFunction, &arg)) // thread create
    {
        cout << "Thread create error" << endl;
        exit(0);
    }

    pthread_join(testthread, (void **)&status);
    return 0;


pthread 사용시에는 주로 pthread_join() 함수를 사용하는데, 
이유는 thread보다 Main Loop가 먼저 끝나면 안되기 때문에 join에서 thread가 끝날 때까지 대기해주어야 합니다.
단, detach의 형태로 thread를 생성한다면 join을 사용하지 않고 Main Loop와 독립적으로 쓰레드를 분리시킬 수 있습니다.  

아래는 thread에서 실행할 함수입니다.
현재 프로그램에서는 "Thread running"을 무한하게 출력하도록 되어있습니다. 

void *ThreadFunction(void *arg)
{
    while(1)
    {
        cout << "Thread running" << endl;
        sleep(1);
    }
}

 

// 전체 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
 
using namespace std;
pthread_t testthread[];
void *ThreadFunction(void *arg);
 
int main(int argc, char *argv[])
{
    int status = 0;
    int arg = 0;
 
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
    if (pthread_create(&testthread, &attr, ThreadFunction, &arg))
    {
        cout << "Thread create error" << endl;
        exit(0);
    }
 
    pthread_join(testthread, (void **)&status);
    return 0;
}
 
void *ThreadFunction(void *arg)
{
    while(1)
    {
        cout << "Thread running" << endl;
        sleep(1);
    }
}

 

// 결과 화면

 

- QThread

QThread 객체는 프로그램 내에서 하나의 제어 스레드를 관리합니다. 
QThreads는 run()에서 실행을 시작하고, 기본적으로 run()은 exec()를 호출하여 이벤트 루프를 시작하고 스레드 내에서 Qt 이벤트 루프를 실행합니다.

QThread를 이용한 Thread 예제입니다.
QThread를 상속받은 TestThread 객체를 생성하고,  Thread와 Main Loop를 Signal/Slot 형태로 연결하는 부분입니다. 

    testthread = new TestThread(this);
    connect(testthread, SIGNAL(ThreadEnd()), this, SLOT(PrintToScreen()));


PrintToScreen() 함수는 1초마다 Thread에서 발생하는 Signal을 받아 수행되는 Slot이고,
on_startButton_clicked() 함수는 UI의 Start 버튼 클릭 시 쓰레드를 시작하는 이벤트 함수입니다.

QThread를 상속받아 구현한 TestThread 클래스는 아래와 같이 구성되어 있고, 

"Insert Your Code" 부분에 쓰레드에서 수행할 동작을 구현하시면 작동하는 것을 볼 수 있습니다.

 

// 전체 코드

mainwindow.h 및 mainwindow.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include "testthread.h"
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
 
private:
    Ui::MainWindow *ui;
    TestThread *testthread;
 
public slots:
    void PrintToScreen();
 
private slots:
    void on_startButton_clicked();
};
 
#endif // MAINWINDOW_H
 
 
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
 
// Constructor
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
 
    // Create Thread Object and Connect Signal/Slot
    testthread = new TestThread(this);
    connect(testthread, SIGNAL(ThreadEnd()), this, SLOT(PrintToScreen()));
}
 
// Destructor
MainWindow::~MainWindow()
{
    testthread->stop();
    delete ui;
}
 
// Slot Process from Multi-Thread Data
void MainWindow::PrintToScreen()
{
    QString string;
    string.sprintf("Thread Slot\n");
    ui->textBrowser->insertPlainText(string);
}
 
// Start Button Event Function
void MainWindow::on_startButton_clicked()
{
    testthread->start();
}

 

// testthread.h 및 testthread.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// testthread.h
#ifndef TESTTHREAD_H
#define TESTTHREAD_H
 
#include <QThread>
#include <QDebug>
#include <unistd.h>
 
class TestThread : public QThread
{
    Q_OBJECT
public:
    explicit TestThread(QObject *parent = 0);
    void stop();
    int m_stopFlag = false;
 
private:
    void run();
 
signals:
    void ThreadEnd();
 
};
 
#endif // TESTTHREAD_H
 
 
// testthread.cpp
#include "testthread.h"
#include "mainwindow.h"
 
TestThread::TestThread(QObject *parent) :
    QThread(parent)
{
 
}
 
void TestThread::run()
{
    while(!m_stopFlag)
    {
        // Insert Your Code
 
        //
        emit ThreadEnd();
        sleep(1);
    }
}
 
void TestThread::stop()
{
    m_stopFlag = true;
}

 

// 결과 화면