궁금증 pintos에서 Condition Variable(condvar)의 동작방식과 존재이유

2025. 5. 25. 13:05개발

Pintos에서 Condition Variable(condvar)의 동작 방식과 구조

Condvar란 무엇인가?

Condition Variable(조건 변수)는 멀티스레드 환경에서 자주 사용되는 동기화 도구 중 하나다. 일반적으로 어떤 특정 조건이 만족될 때까지 스레드를 대기 상태로 만들고, 그 조건이 충족되었을 때 다시 깨어나게 하기 위한 메커니즘이다.

흔히 cond_wait(), cond_signal(), cond_broadcast()의 세 가지 주요 함수로 사용된다.

예시로 이해하기: 생산자-소비자 문제

Condition Variable이 필요한 이유를 이해하기 위해 가장 대표적인 예시인 생산자-소비자 문제를 살펴보자.

  • 생산자는 버퍼가 가득 찬 상태에서는 데이터를 더 넣을 수 없기 때문에, 버퍼에 공간이 생길 때까지 기다려야 한다.
  • 소비자는 버퍼가 비어 있는 상태에서는 데이터를 꺼낼 수 없기 때문에, 데이터가 들어올 때까지 기다려야 한다.

이때 단순히 lock을 이용한 상호배제만으로는 "조건이 만족되었는지"를 제대로 처리할 수 없다. 그래서 조건 자체를 기다릴 수 있도록 도와주는 Condition Variable이 필요한 것이다.

 Condition Variable의 역할

Condition Variable은 "조건이 만족되기 전까지 스레드를 block 상태로 만들고", "조건이 만족되면 해당 스레드를 다시 깨우기 위한 도구"다.

단순한 lock은 동시에 접근하는 것을 막을 수는 있지만, 조건 자체를 기다리는 기능은 없다. 즉, 어떤 상태(state)가 만족되기를 기다리는 스레드를 명확하게 관리하기 위해 condvar가 필요하다.

 Pintos의 condvar는 조금 다르다

실제 운영체제에서는 보통 조건 변수를 다음과 같이 사용한다:


lock_acquire(&lock);
while (!조건) {
    cond_wait(&cond, &lock);
}
lock_release(&lock);

하지만 Pintos의 condvar는 조건을 직접 검사하지 않는다.
예를 들어, priority-condvar 테스트에서는 단순히 스레드들이 cond_wait()로 잠들고, 우선순위(priority) 순서대로 잘 깨어나는지를 검증하는 구조로 되어 있다.

 그럼 cond->waiters 리스트는 왜 따로 관리할까?

  • 만약 ready_list에 넣는다면, 이 스레드가 어떤 조건을 기다리는지 알 수 없다.
  • ready_listCPU 실행을 기다리는 스레드들을 위한 큐다. 조건을 기다리는 것과는 다르다.
  • 따라서 cond->waiters라는 별도의 리스트로 관리하여 조건 대기 스레드들을 구분한다.

 Condvar의 동작 흐름

  1. cond_wait()을 호출하면 struct semaphore_elem을 하나 생성하여 cond->waiters에 추가한다.
  2. 그 후, 현재 스레드는 락을 release하고, sema_down()을 호출하여 블록된다.
  3. cond_signal()이 호출되면, cond->waiters 리스트에서 우선순위가 가장 높은 세마포어를 선택한다.
  4. 선택된 세마포어에 대해 sema_up()을 호출하여 대기 중인 스레드를 깨운다.
  5. 스레드는 깨어나면서 다시 락을 획득하고 나머지 작업을 계속 수행한다.

구조 요약

  • cond->waitersstruct semaphore_elem 타입의 리스트다.
  • semaphore_elemstruct semaphore를 포함한다.
  • 스레드는 대기 시, 자신 전용 세마포어에 블록되고 waiters 리스트에 추가된다.
  • cond_signal()sema_priority_compare()를 통해 우선순위 높은 세마포어를 선택해 깨운다.

// cond_signal 구현 예시
void cond_signal(struct condition *cond, struct lock *lock) {
    if (!list_empty(&cond->waiters)) {
        list_sort(&cond->waiters, sema_priority_compare, NULL);
        struct semaphore_elem *sema_elem = 
            list_entry(list_pop_front(&cond->waiters), struct semaphore_elem, elem);
        sema_up(&sema_elem->semaphore);
    }
}

핵심 비교: ready_list vs cond->waiters

Condition Variable과 ready_list의 역할을 혼동하지 않아야 한다.

구분 ready_list cond->waiters
의미 실행 준비가 완료된 스레드들 특정 조건을 기다리는 스레드들
상태 바로 스케줄링 가능 조건 충족 전까지는 block 상태
목적 CPU 자원 요청 조건 만족 대기

결론 정리

  • Condition Variable은 조건을 기다리는 스레드를 블록시키고, 조건이 충족될 때 깨우는 동기화 도구다.
  • Pintos에서는 조건 검사는 생략되어 있고, condvar 구조가 우선순위 기반 스레드 깨어남을 검증하는 데에 집중되어 있다.
  • cond->waiters는 단순히 깨어날 준비가 된 것이 아니라, 특정 조건을 기다리는 스레드의 모음이다.