4. atomic 메모리 순서(memory_order)와 happens-before

난이도 상 해설 보기 →

결함을 모두 찾고 원인·수정안·더 나은 설계를 제시하라. 마커 (A)(B) 는 주목 위치 힌트다.

결함 코드 · C++
// ============================================================================
// [언어 내부동작 문제] C++ - atomic 메모리 순서(memory_order)와 happens-before
// ----------------------------------------------------------------------------
// 주제: std::atomic 의 memory_order(relaxed / acquire / release / seq_cst)가
//       스레드 간 가시성과 재배치에 어떤 의미를 갖는지.
//
// 아래는 한 스레드가 데이터를 준비하고 플래그로 "완료"를 알리면, 다른 스레드가
// 그 플래그를 보고 데이터를 읽는 전형적인 메시지 패싱(message passing) 패턴이다.
// payload 는 일반(비원자) 변수이고, ready 만 atomic 이다.
//
// 과제(코드를 고치는 문제가 아니라, 내부 동작을 예측·설명하는 문제):
//   1) producer/consumer 가 아래처럼 memory_order_relaxed 를 쓸 때, consumer 의 (4)에서
//      항상 42 가 보이는가? payload 접근은 안전한가? 그 이유를 메모리 모델로 설명하라.
//   2) (2)를 release, (3)를 acquire 로 바꾸면 무엇이 "synchronizes-with / happens-before"
//      로 보장되는가? 그때 (4)의 결과와 데이터 경합 여부는?
//   3) memory_order_seq_cst 가 release/acquire 보다 더 보장하는 것은 무엇이며(예: 다중
//      변수 불변식/store-buffering), relaxed 가 정당한 경우(예: 단순 카운터)는 언제인가?
//   (먼저 직접 예측을 적은 뒤 answer.md 와 대조할 것)
// ============================================================================

#include <atomic>
#include <thread>
#include <iostream>

std::atomic<bool> ready{false};
int               payload = 0;     // 일반(비원자) 변수

void producer() {
    payload = 42;                                       // (1) 데이터 준비
    ready.store(true, std::memory_order_relaxed);       // (2) 완료 신호
}

void consumer() {
    while (!ready.load(std::memory_order_relaxed)) {     // (3) 신호 대기(스핀)
        /* busy wait */
    }
    std::cout << payload << "\n";                        // (4) 데이터 읽기
}

int main() {
    std::thread t1(producer);
    std::thread t2(consumer);
    t1.join();
    t2.join();
    return 0;
}
내 리뷰 · C++
내 답안 · 자동 저장

작성 후 위 해설 보기에서 모범 해설과 대조하세요.