본문 바로가기
프로그래밍

👨‍💻 [C++] C++ 에서 std::condition_variable 은 무엇이며, 어떻게 활용할 수 있나요?

by 밝음의기둥 2025. 1. 23.
반응형

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


👨‍💻 안녕하세요, 윌리 프로젝트의 윌리 입니다.

C++ 에서 std::condition_variable 은 무엇이며, 어떻게 활용할 수 있는지 간략히 알아보았습니다.


질문 >

C++ 에서 std::condition_variable 은 무엇이며, 어떻게 활용할 수 있나요?

답변 >

std::condition_variable란?

std::condition_variable은 C++ 표준 라이브러리에서 제공하는 동기화 도구입니다. 이를 사용하면 스레드 간의 통신을 효율적으로 구현할 수 있습니다. 주로 하나의 스레드가 특정 조건을 만족할 때까지 다른 스레드가 대기하고, 조건이 만족되면 이를 알리는 방식으로 동작합니다.


std::condition_variable의 주요 특징

  1. 대기와 알림:
    • 한 스레드가 조건을 기다리는 동안 다른 스레드가 조건을 충족시킨 뒤 알림을 보냅니다.
    • 조건이 충족되었을 때만 대기 중인 스레드가 실행됩니다.
  2. 뮤텍스와 함께 사용:
    • std::condition_variable은 std::mutex(뮤텍스)와 함께 사용되어 데이터 접근을 보호합니다.
    • 대기와 알림 과정에서 데이터 경쟁 조건(race condition)을 방지합니다.
  3. 잠재적인 스레드 절전:
    • 조건이 충족되지 않은 경우, 대기 중인 스레드는 절전 상태로 전환됩니다.
    • 이를 통해 CPU 자원을 절약할 수 있습니다.

사용 가능한 주요 멤버 함수

  1. wait():
    • 호출한 스레드를 조건이 충족될 때까지 대기 상태로 만듭니다.
    • 반드시 뮤텍스와 함께 사용해야 하며, 조건을 확인하는 람다를 인수로 전달할 수 있습니다.
  2. notify_one():
    • 대기 중인 스레드 중 하나를 깨웁니다.
  3. notify_all():
    • 대기 중인 모든 스레드를 깨웁니다.

std::condition_variable 사용법

1. 기본 예제: notify_one()

#include <iostream>
#include <thread>
#include <condition_variable>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; }); // 조건이 충족될 때까지 대기
    std::cout << "Worker thread is running!" << std::endl;
}

int main() {
    std::thread t(worker);

    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true; // 조건 충족
    }
    cv.notify_one(); // 대기 중인 스레드 하나를 깨움

    t.join();
    return 0;
}

출력 예시:

Worker thread is running!


2. notify_all()로 여러 스레드 알림

#include <iostream>
#include <thread>
#include <condition_variable>
#include <vector>

std::mutex mtx;
std::condition_variable cv;
bool ready = false;

void worker(int id) {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return ready; }); // 조건 충족 대기
    std::cout << "Worker thread " << id << " is running!" << std::endl;
}

int main() {
    const int numThreads = 3;
    std::vector<std::thread> threads;

    for (int i = 0; i < numThreads; ++i) {
        threads.emplace_back(worker, i);
    }

    {
        std::lock_guard<std::mutex> lock(mtx);
        ready = true; // 조건 충족
    }
    cv.notify_all(); // 모든 대기 중인 스레드 깨움

    for (auto& t : threads) {
        t.join();
    }
    return 0;
}

출력 예시:

Worker thread 0 is running!
Worker thread 1 is running!
Worker thread 2 is running!


실제 활용 예제

3. 생산자-소비자 문제

#include <iostream>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>

std::queue<int> buffer;
const int bufferSize = 5;

std::mutex mtx;
std::condition_variable cv;

void producer() {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return buffer.size() < bufferSize; }); // 버퍼가 비면 생산 가능
        buffer.push(i);
        std::cout << "Produced: " << i << std::endl;
        cv.notify_all(); // 소비자 알림
    }
}

void consumer() {
    for (int i = 0; i < 10; ++i) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return !buffer.empty(); }); // 버퍼가 비어있지 않으면 소비 가능
        int item = buffer.front();
        buffer.pop();
        std::cout << "Consumed: " << item << std::endl;
        cv.notify_all(); // 생산자 알림
    }
}

int main() {
    std::thread prod(producer);
    std::thread cons(consumer);

    prod.join();
    cons.join();

    return 0;
}

출력 예시:

Produced: 0
Consumed: 0
Produced: 1
Consumed: 1
Produced: 2
Consumed: 2
...


주의사항

  1. 스풉리엇(wait())의 잠금 해제와 재획득:
    • wait()는 대기 중인 동안 뮤텍스를 잠금 해제하지만, 조건이 충족되면 뮤텍스를 다시 획득합니다.
  2. 조건 확인 필수:
    • 대기 상태에서 깨어난 뒤에도 조건을 반드시 확인해야 합니다.
    • 스레드 기아 문제 또는 허위 깨어남(spurious wakeup)을 방지하려면 cv.wait(lock, condition) 형태로 사용하는 것이 좋습니다.
  3. 뮤텍스와 조건 변수의 올바른 사용:
    • std::condition_variable는 항상 std::mutex와 함께 사용해야 합니다. std::unique_lock<std::mutex>를 사용하는 것이 권장됩니다.

결론

std::condition_variable은 스레드 간의 동기화효율적인 통신을 위한 강력한 도구입니다. 이를 통해 스레드가 특정 조건을 만족할 때만 실행되도록 제어할 수 있습니다.

  • 주요 활용:
    • 생산자-소비자 패턴 구현.
    • 스레드 풀 관리.
    • 특정 조건 충족 시 이벤트 처리.

std::condition_variable은 멀티스레드 프로그램의 안정성과 효율성을 높이는 데 중요한 역할을 합니다. 이를 올바르게 사용하면 데이터 무결성을 유지하면서 스레드 간의 효율적인 협력을 구현할 수 있습니다.



🎬 유튜브 채널 🎬

 

위로그@WiLog

📢 안녕하세요, 위로그@WiLog 시청자 여러분, 저는 윌리(Willee) 입니다. 📢 위로그@WiLog 는 자기계발을 목적으로 하는 채널 입니다. 📢 오늘도 즐겁게~ 자신을 위한 계발을 함께 해보아요~ d^_^b 📌

www.youtube.com

🎬 치지직 채널 🎬

 

위로그 채널 - CHZZK

지금, 스트리밍이 시작됩니다. 치지직-

chzzk.naver.com


반응형