본문 바로가기
프로그래밍/C++

C++ 쓰레드(thread)

by comflex 2023. 2. 21.
728x90
반응형

C++11부터는 멀티스레드 프로그래밍을 지원하는 thread 라이브러리를 제공합니다. 이 라이브러리를 사용하여 여러 개의 스레드를 생성하고 동시에 실행할 수 있습니다.

 

스레드 생성

C++의 thread 라이브러리를 사용하여 스레드를 생성하는 방법은 다음과 같습니다.

 

#include <thread>

void thread_function() {
    // 스레드에서 실행할 작업
}

int main() {
    std::thread t(thread_function);
    // 스레드 실행 중
    t.join();
    // 스레드 종료
    return 0;
}

위 코드에서는 thread_function 함수를 스레드에서 실행하는 스레드 객체 t를 생성합니다. thread 객체를 생성할 때 인자로 스레드에서 실행할 함수를 전달합니다. 생성된 t 객체를 join() 함수를 호출하여 스레드를 기다리고 종료합니다. 만약 join() 함수를 호출하지 않으면 프로그램이 종료되는 시점에 스레드가 강제로 종료됩니다.

반응형

함수 객체와 람다 함수를 이용한 스레드 생성

위에서 thread_function 함수를 인자로 전달하여 스레드를 생성하였습니다. 하지만, 함수 포인터 또는 함수 이름만 전달할 수 있는 것은 아닙니다. 함수 객체와 람다 함수도 인자로 전달할 수 있습니다.

 

#include <thread>
#include <iostream>

class Worker {
public:
    void operator()() {
        std::cout << "Worker Thread ID: " << std::this_thread::get_id() << std::endl;
    }
};

int main() {
    std::cout << "Main Thread ID: " << std::this_thread::get_id() << std::endl;
    std::thread t(Worker());
    t.join();
    return 0;
}

위 코드에서는 Worker 클래스를 이용하여 스레드에서 실행할 작업을 구현하였습니다. Worker 클래스는 operator() 함수를 오버로딩하여 스레드에서 실행될 작업을 구현하였습니다. Worker() 객체를 이용하여 스레드 객체 t를 생성하였습니다.

또한, std::this_thread::get_id() 함수를 이용하여 현재 스레드의 ID를 출력하였습니다. main 함수에서는 메인 스레드의 ID를 출력하였고, Worker 클래스에서는 스레드 함수가 실행되는 스레드의 ID를 출력하였습니다.

스레드 동기화

멀티스레드 프로그래밍을 할 때, 공유자원에 대한 접근을 동기화해야 합니다. 스레드가 공유자원에 접근할 때는 다른 스레드가 접근하지 못하도록 제한을 둬야 합니다. 이를 위해 C++에서는 mutexlock_guard를 제공합니다.

 

#include <thread>
#include <mutex>
#include <iostream>

std::mutex mtx;

void thread_function(int n) {
    std::lock_guard<std::mutex> lock(mtx);
    std::cout << "Thread " << n << " is running." << std::endl;
}

int main() {
    std::thread t1(thread_function, 1);
    std::thread t2(thread_function, 2);
    t1.join();
    t2.join();
    return 0;
}

위 코드에서는 mutex 객체 mtx를 생성하여 lock_guard 객체 lock으로 래핑하였습니다. lock_guard 객체는 생성될 때 mutex 객체를 잠근 상태로 만들고, 소멸될 때 mutex 객체를 해제합니다.

thread_function 함수에서는 lock_guard 객체 lock을 생성하여 mtx 객체를 잠근 후, 출력을 수행합니다. 이 때, 다른 스레드가 mtx 객체를 접근하지 못하도록 보호합니다.

main 함수에서는 thread_function 함수를 각각 스레드로 실행하고, join() 함수를 호출하여 스레드를 기다리고 종료합니다.

스레드의 반환값

스레드에서 실행한 작업의 결과값을 메인 스레드에서 사용해야 할 때가 있습니다. 이를 위해 C++에서는 std::thread 객체의 joinable() 함수를 이용하여 스레드가 종료될 때까지 대기한 후, std::thread 객체의 get() 함수를 이용하여 반환값을 가져올 수 있습니다.

 

#include <thread>
#include <iostream>

void thread_function(int n, int& result) {
    result = n * n;
}

int main() {
    int result = 0;
    std::thread t(thread_function, 2, std::ref(result));
    if (t.joinable()) {
        t.join();
        std::cout << "Result: " << result << std::endl;
    }
    return 0;
}

위 코드에서는 thread_function 함수에서 result 변수에 값을 대입하도록 구현하였습니다. thread 객체 t를 생성할 때 result 변수를 레퍼런스로 전달하고, joinable() 함수를 호출하여 스레드가 종료될 때까지 대기합니다.

 

결론

이번에는 C++의 thread 라이브러리에 대해 살펴보았습니다. 스레드를 생성하는 방법과 스레드 간의 동기화를 위한 mutex와 lock_guard를 사용하는 방법, 스레드의 반환값을 가져오는 방법에 대해 다루었습니다.

스레드는 여러 작업을 동시에 수행할 수 있도록 해주는 강력한 도구입니다. 하지만 스레드를 사용할 때는 공유자원에 대한 접근 제한을 두어야 하며, 스레드 간의 동기화 문제를 주의해야 합니다.

C++의 thread 라이브러리는 스레드 관리를 쉽게 할 수 있도록 많은 기능을 제공합니다. 스레드를 사용할 때는 문제가 생길 가능성이 있는 부분에 대해 충분히 고려한 후 구현해야 합니다.

728x90
반응형

'프로그래밍 > C++' 카테고리의 다른 글

C++ std::copy_if  (0) 2023.03.02
C++ std::remove_if  (0) 2023.03.02
C++ transform  (0) 2023.02.18
C++ Functor(함수 객체)  (2) 2023.02.17
C++ std::sort  (2) 2023.01.04