c++

C++ 멀티스레딩 프로그래밍과 동기화 기법

난개발자 2025. 2. 3. 21:10
728x90

1. 멀티스레딩(Multithreading)이란?

멀티스레딩은 하나의 프로그램이 동시에 여러 작업을 수행할 수 있게 해주는 기술입니다. C++에서는 thread 라이브러리를 통해 멀티스레딩을 구현할 수 있습니다.

(1) 스레드의 기본 개념

  • 스레드(Thread): 프로세스 내에서 실행되는 가장 작은 단위
  • 멀티스레딩을 통해 병렬 처리가 가능하여 성능을 향상시킬 수 있습니다.

2. C++에서 스레드 사용하기

(1) 기본 스레드 생성 및 실행

#include <iostream>
#include <thread>
using namespace std;

void printMessage() {
    cout << "스레드에서 실행 중입니다." << endl;
}

int main() {
    // 스레드 생성
    thread t(printMessage);

    // 메인 스레드에서 실행
    cout << "메인 스레드에서 실행 중입니다." << endl;

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

    return 0;
}

출력 결과:

메인 스레드에서 실행 중입니다.
스레드에서 실행 중입니다.

(2) 인자 전달 스레드

스레드 함수에 인자를 전달할 수 있습니다.

#include <iostream>
#include <thread>
using namespace std;

void printNumber(int num) {
    cout << "숫자: " << num << endl;
}

int main() {
    thread t(printNumber, 42);
    t.join();
    return 0;
}

출력 결과:

숫자: 42

3. 동기화(Synchronization)란?

동기화는 여러 스레드가 공유 자원에 동시에 접근할 때 발생할 수 있는 문제(데이터 충돌)를 방지하기 위한 기술입니다.

(1) 데이터 경쟁(Race Condition)

  • 두 개 이상의 스레드가 동일한 자원에 접근할 때 발생하는 예측 불가능한 결과
  • 이를 방지하기 위해 **뮤텍스(Mutex)**를 사용합니다.

4. 뮤텍스(Mutex) 사용하기

(1) 기본 뮤텍스 사용법

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

mutex mtx;  // 뮤텍스 객체 생성

void printSafeMessage(const string& message) {
    mtx.lock();
    cout << message << endl;
    mtx.unlock();
}

int main() {
    thread t1(printSafeMessage, "스레드 1 실행 중");
    thread t2(printSafeMessage, "스레드 2 실행 중");

    t1.join();
    t2.join();

    return 0;
}

출력 결과:

스레드 1 실행 중
스레드 2 실행 중

(2) lock_guard를 활용한 뮤텍스 관리

lock_guard는 뮤텍스를 자동으로 관리하여 lockunlock을 명시적으로 작성할 필요가 없습니다.

#include <iostream>
#include <thread>
#include <mutex>
using namespace std;

mutex mtx;

void printSafeMessage(const string& message) {
    lock_guard<mutex> lock(mtx);  // 자동으로 뮤텍스 잠금 및 해제
    cout << message << endl;
}

int main() {
    thread t1(printSafeMessage, "스레드 1 실행 중");
    thread t2(printSafeMessage, "스레드 2 실행 중");

    t1.join();
    t2.join();

    return 0;
}

5. 조건 변수(Condition Variable)

조건 변수는 스레드 간의 통신을 가능하게 하며, 특정 조건이 충족될 때까지 스레드를 대기 상태로 유지합니다.

(1) 조건 변수 사용 예제

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;

mutex mtx;
condition_variable cv;
bool ready = false;

void printMessage() {
    unique_lock<mutex> lock(mtx);
    cv.wait(lock, [] { return ready; });  // ready가 true가 될 때까지 대기
    cout << "스레드가 실행되었습니다." << endl;
}

int main() {
    thread t(printMessage);

    this_thread::sleep_for(chrono::seconds(2));  // 2초 대기
    {
        lock_guard<mutex> lock(mtx);
        ready = true;
    }
    cv.notify_one();  // 대기 중인 스레드 깨우기

    t.join();
    return 0;
}

출력 결과:

스레드가 실행되었습니다.

6. 멀티스레딩 실전 예제: 병렬 합계 계산

멀티스레딩을 활용하여 배열의 합계를 병렬로 계산하는 예제입니다.

#include <iostream>
#include <vector>
#include <thread>
using namespace std;

void partialSum(const vector<int>& data, int start, int end, int& result) {
    result = 0;
    for (int i = start; i < end; ++i) {
        result += data[i];
    }
}

int main() {
    vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int result1 = 0, result2 = 0;

    // 두 개의 스레드를 사용하여 배열을 나누어 합계 계산
    thread t1(partialSum, cref(data), 0, data.size() / 2, ref(result1));
    thread t2(partialSum, cref(data), data.size() / 2, data.size(), ref(result2));

    t1.join();
    t2.join();

    cout << "총 합계: " << result1 + result2 << endl;
    return 0;
}

출력 결과:

총 합계: 55

 

728x90