일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 비밀 코드 해독
- lock based stack
- 홀짝트리
- LCS
- DirectX12
- lock free stack
- c++
- boj 15724
- 프로그래밍공부
- boj 21921
- 브루트포스
- PCCE
- DirectX
- pcce 기출문제 풀이
- boj 11053
- 색종이와가위
- pccp 기출문제 풀이
- lock based queue
- boj 1958
- tessellation
- 2025 프로그래머스 코딩챌린지 1차예선
- 데이터 체커
- boj 1074
- boj 20207
- orthographic projection
- dp
- boj 6443
- 지게차와 크레인
- render target
- boj 22942
- Today
- Total
오구의코딩모험
[Server] Condition Variable, Future 본문
멀티스레드 동기화와 비동기 처리: condition_variable & future
서버 개발에서는 멀티스레드를 다룰 때 반드시 스레드 간 동기화와 비동기 처리에 대한 이해가 필요합니다.
오늘은 'condition_variable'을 이용한 생산자-소비자 패턴 구현, 그리고 'future', 'promise', 'packaged_task'를 사용한 비동기 처리 방식에 대해 공부했습니다.
1. condition_variable
핵심 개념
- condition_variable은 한 스레드가 특정 조건을 충족했을 때 다른 스레드에게 알림을 보내는 동기화 도구입니다.
- 일반적으로 mutex와 함께 사용하며, 생산자-소비자 구조에 적합합니다.
아래는 Producer 스레드가 데이터를 추가하고 Consumer 스레드가 이를 소비하는 구조입니다.
std::condition_variable cv;
std::mutex m;
std::queue<int32_t> q;
void Producer()
{
while (true)
{
{
std::unique_lock<std::mutex> lock(m);
q.push(100);
}
cv.notify_one(); // 대기 중인 스레드 중 하나를 깨움
std::this_thread::sleep_for(10000ms);
}
}
void Consumer()
{
while (true)
{
std::unique_lock<std::mutex> lock(m);
cv.wait(lock, []() { return q.empty() == false; });
int32_t data = q.front();
q.pop();
std::cout << data << std::endl;
}
}
※ 주의사항 : Spurious Wakeup
조건을 만족하지 않았는데도 스레드가 깨어날 수 있습니다.
이를 Spurious Wakeup이라고 하며, wait()에 반드시 조건 함수(람다)를 포함해 방지해야 합니다.
2. std::future & async
int64_t Calculate()
{
int64_t sum = 0;
for (int32_t i = 0; i < 100'000; i++)
sum += i;
return sum;
}
std::future<int64_t> future = std::async(std::launch::async, Calculate);
std::future_status status = future.wait_for(1ms);
int64_t sum = future.get(); // 결과 필요 시 대기하고 받아오기
개념 요약
- std::async을 사용하면 함수를 비동기적으로 실행할 수 있습니다.
- 실행 결과는 future를 통해 나중에 받아올 수 있습니다.
3. std::promise
void PromiseWorker(std::promise<std::string>& promise)
{
promise.set_value("Secret Message");
}
std::promise<std::string> promise;
std::future<std::string> future = promise.get_future();
std::thread t(PromiseWorker, std::move(promise));
std::string message = future.get();
t.join();
핵심 개념
- promise는 값을 나중에 줄 것을 약속하고, future는 그 값을 기다리는 역할을 합니다.
- 서로 다른 스레드 간 데이터 전달이 필요한 경우에 유용합니다.
4. std::packaged_task
void TaskWorker(std::packaged_task<int64_t(void)>&& task)
{
task(); // 포장된 함수 실행
}
std::packaged_task<int64_t(void)> task(Calculate);
std::future<int64_t> future = task.get_future();
std::thread t(TaskWorker, std::move(task));
int64_t sum = future.get();
t.join();
개념 요약
- packaged_task는 특정 함수를 포장하여 나중에 실행하고, 실행 결과를 future로 받을 수 있게 합니다.
5. 정리 및 활용법
어떤 상황에 어떤 도구를 써야 할까?
*** condition_variable : 반복적으로 조건을 만족하는 경우에 다른 스레드에 알려주고 싶을 때
*** future + async : 단순히 비동기 함수 실행 + 결과 대기가 필요한 경우
*** promise : 한 스레드에서 값을 계산하여 다른 스레드로 전달할 때
*** packaged_task : 실행 시점을 컨트롤하면서 결과도 받아야 하는 경우
결론
이번 학습을 통해 스레드 간 통신과 데이터 처리 방식을 다양한 방법으로 처리할 수 있음을 배웠습니다.
특히 condition_variable은 고전적인 동기화 도구로 유용하고, future, promise, packaged_task는 좀 더 선언적이고 간편한 방식으로 스레드 간 결과 전달을 가능하게 합니다.

'Game > Server' 카테고리의 다른 글
[Server] Lock Free Stack (上편) (0) | 2025.04.02 |
---|---|
[Server] 메모리 모델, Thread Local Storage (= TLS), Lock-Based Stack/Queue (0) | 2025.03.31 |
[Server] SpinLock, Sleep, Event (0) | 2025.03.17 |
[Server] Game Server, Multi Thread, Atomic, Lock, Dead Lock (0) | 2025.01.16 |