프로그래밍 언어/C & C++ 정리

쓰레드 기본 사용법

뽀또치즈맛 2024. 11. 28. 22:56

멀티스레드 프로그래밍은 멀티프로세서가 장착된 컴퓨터 시스템에서 중요한 기법이다.

멀티스레드 프로그래밍을 이용하면 시스템에 있는 여러 프로세서 유닛을

병렬로 사용하는 프로그램을 작성할 수 있다.

시스템에 프로세서 유닛이 장착되는 방식은 다양하다.

독립적인 CPU 프로세서 칩이 여러 개 달려 있을 수 있고,

한 프로세스 칩 안에 코어라 부르는 독립 CPU가 여러 개 있을 수 있고,

또 어떤 시스템은 두 가지 방식이 혼합되기도 한다.

이렇게 프로세스 유닛이 여러 개 달린 프로세서를 흔히 멀티코어 프로세서라 부른다.

사실 이렇게 프로세서가 여러 개 달린 시스템이 나온지 꽤 오래되었지만

이제는 서버부터 개인용 컴퓨터, 심지어 스마트폰에 이르기까지 거의 모든 시스템이

멀티코어 프로세서를 사용한다.

이처럼 멀티코어 프로세서가 보변화되었기에

멀티스레드 어플리케이션을 작성할 줄 아는 것이 중요하다.

 

이제 C++ STD 스레드 기본 사용법을 알아보자.

 

 

1. 기본 사용법

#include <iostream>
#include <thread>

using namespace std;

void threadFunction() {
    for (int i = 0; i < 5; ++i) {
        cout << "스레드에서 작업 중: " << i << endl;
    }
}

int main() {
    // 스레드 생성 및 시작
    thread t(threadFunction);

    // 메인 스레드에서 수행할 작업
    for (int i = 0; i < 3; ++i) {
        cout << "메인 스레드에서 작업 중: " << i << endl;
    }

    // 스레드 종료 대기
    t.join();

    return 0;
}

 

 

2. 람다식 전달하기

#include <iostream>
#include <thread>

using namespace std;

int main() {
    // 람다식을 사용하여 스레드 생성 및 실행
    thread t([]() {
        for (int i = 0; i < 5; ++i) {
            cout << "스레드 t에서 작업 중: " << i << endl;
        }
    });

    // 메인 스레드에서 수행할 작업
    for (int i = 0; i < 3; ++i) {
        cout << "메인 스레드에서 작업 중: " << i << endl;
    }

    // 스레드 종료 대기
    t.join();

    return 0;
}

 

 

3. 멤버함수 전달하기

#include <iostream>
#include <thread>

using namespace std;

class MyClass {
public:
    void memberFunction(int x) {
        for (int i = 0; i < x; ++i) {
            cout << "작업 중: " << i << endl;
        }
    }
};

int main() {
    MyClass myObject;
    // 첫번째 인자로 멤버 함수를 전달할 때는 두번째 인자로 해당 객체 인스턴스를 같이 전달한다.
    thread t(&MyClass::memberFunction, &myObject, 5);

    t.join(); // 스레드 종료 대기

    return 0;
}

 

 

여기서 계속 쓰이는 join은 뭘까?

 

join 함수는 스레드의 종료를 기다리는 함수로,

join() 함수가 호출되면 스레드가 실행을 마칠 때까지 리턴되지 않으며

이를 호출한 스레드는 블록된 상태로 해당 스레드의 작업이 완료될 때까지 대기한다.

 

이렇게 스레드의 종료를 기다려야 하는 이유는

스레드 객체가 스코프를 벗어가나거나 소멸될 때

해당 스레드 함수가 여전히 실행중인 경우 std::terminate() 함수가 호출되고

프로그램이 비정상적으로 종료되기 때문이다.

 

때문에 thread의 생명주기 내에서 리소스가 정상적으로 정리될 수 있도록

join() 함수를 통해 기다릴 필요가 있다.