본문 바로가기

개발 관련 기타/C++

C++) Reader-Writer 문제로 본 mutex와 condition variable

Mutex

  • lock 함수로 임계 구역 (critical section) 진입 전 자신만 임계 구역에 들어가겠다고 함
  • unlock 함수로 임계 구역 탈출 후 다른 사람들도 임계 구역에 진입 가능하도록 만듬

 

Condition Variable

  • wait 시 인자로 받은 mutex를 unlock 함
  • notify_one 함수로 잠자는 것들 중 하나를 깨울 수 있음
  • notify_all 함수로 잠자는 것들 모두를 깨울 수 있음

 

Reader-Writer 문제에서 mutex와 condition variable을 사용한다면

 

<iostream>
<mutex>
<condition_variable>

std::mutex mtx;
std::condition_variable cv;
int num_writers_waiting;
bool writer_active;
int num_readers_active;

int readStart() {
	std::lock_guard<std::mutex> lock(mtx);
    num_readers_active++;
    while (num_writers_waiting > 0 || writer_active) {
    	cv.wait();
    }
} // as goes out of scope, mtx unlocked (lock_guard 기능)

int readEnd() {
	std::lock_guard<std::mutex> lock(mtx);
    num_readers_active--;
    if (num_readers_active == 0) cv.notify_all();
} // as goes out of scope, mtx unlocked (lock_guard 기능)

int writeStart() {
	std::lock_guard<std::mutex> lock(mtx);
    num_writers_waiting++;
    while (num_readers_active > 0 || writer_active) {
    	cv.wait();
    }
    num_writers_waiting--;
    writer_active = true;
} // as goes out of scope, mtx unlocked (lock_guard 기능)

int writeEnd() {
	std::lock_guard<std::mutex> lock(mtx);
    while (num_readers_active > 0 || writer_active) {
    	cv.wait();
    }
    writer_active = false;
    cv.notify_all();
} // as goes out of scope, mtx unlocked (lock_guard 기능)

코드 분석

  • std::lock_guard를 사용하면 C++ 의 RAII 원칙을 따르면서 일일히 여러 경우에 관해 unlock 함수를 써줄 필요가 없다
    • RAII (Resource Acquisition Is Initialization): 선언 시에 메모리가 할당되고 scope에 벗어나 정리될 때 자동으로 메모리도 해제 됨
  • 위 예제는 writer를 우선으로 해서 1명이라도 write를 기다리고 있으면 더 이상 reader를 늘리지 않습니다.
  • condition variable은 위 예제 처럼 mutexcondition을 나타낼 변수와 함께 사용됩니다.
    • 예) writer_active 가 true 라면 (누군가 쓰고 있다면) condition variable의 wait을 불러 mutex lock을 해제하고 다른 이들이 notify를 호출해 깨워주는 것을 기다립니다.
    • conditon variable과 mutex를 같이 사용하는 이유는 condition을 나타낼 변수 또한 수정하는데 있어서 경쟁 상태가 발생 할 수 있기 때문에 condition 변수 수정 전 lock을 잡고 condition 변수 수정 또한 atomic 하게 이루어지게 하기 위함입니다.
  • notify를 통해 깨워났을 때 다시 lock을 갖게 됩니다.