Boost의 shared_mutex

Pinterest

글 : 이승용

MongoDB는 C++로 개발된 NoSQL 시스템이다. 따라서 많이 사용되는 C++ 프레임워크인 boost를 MongoDB가 사용한다. MongoDB의 락 시스템은 boost의 shared_mutex를 사용하여 구현되었다. Shared_mutex는 muti-read and single write를 지원하는 쓰레드 상의 동기화를 지원해 주는 boost의 락 라이브러리이다. 아래의 코드는 boost를 이용한 shared_mutex를 활용한 락의 기본 사용을 보여준다.
 
[리스트 1] shared_mutex를 이용한 예제 프로그램

boost::shared_mutex _access; 
void reader() 
{ 
	// get shared access 
	boost::shared_lock lock(_access); 
	
	// now we have shared access 
} 
	
void writer() 
{ 
	// get upgradable access 
	boost::upgrade_lock lock(_access); 
	
	// get exclusive access 
	boost::upgrade_to_unique_lock uniqueLock(lock); 
	// now we have exclusive access 
}

 
Boost에서는 일반 mutex의 기본 개념보다 좀 더 유연한 형태의 락을 설정할 수 있도록 upgradable mutex를 제공한다. 정확하게 표현하면, upgradable mutex는 mutex의 가능성을 판단하여 여러 개의 쓰레드가 동시에 락을 공유할 수 있도록 만든 기법이다. 이러한 기법을 multi reader and single write 기술이라고 말한다. 읽기는 데이터 수정이 발생되지 않기 때문에 여러 개의 읽기 연산이 수행되어도 공유하는 데이터에 영향을 주지 않는다. 반면, 쓰기 연산은 공유하고 있는 데이터 수정이 발생하기 때문에 다른 쓰레드에서 읽기 또는 쓰기 연산과 충돌되어 데이터 일관성 문제가 발생한다. 즉 쓰기 연산은 배타적으로 락이 설정되어야 한다.

Upgradable mutex는 이와 같이 읽기 연산은 쓰기 연산이 없는 동안, 아무런 제재 없이 읽기가 원활하게 이루어져야 하고, 쓰기 연산은 다른 쓰레드들의 읽기 또는 쓰기 연산이 자신의 쓰기 연산이 완료될 때까지 사용할 수 없도록 만들어 준다.

쓰기 연산을 수행하기 위한 절차를 생각해 보자. 쓰기 연산은 공유 데이터에 접근하기 위해 현재 공유 데이터를 사용하고 있는 쓰레드들이 있는지 판단한다. 만약 공유 데이터를 사용하고 있는 쓰레드가 있다면, 해당 쓰레드가 사용을 완료할 때까지 기다려야 한다. 자신을 제외한 모든 쓰레드가 공유 데이터의 사용을 완료하였다면, 대기 중이던 쓰기 연산은 배타적 락을 설정하여 다른 쓰레드들이 자신의 작업이 완료될 때까지 공유 데이터에 접근할 수 없도록 만든다.

반대로, 읽기 연산은 현재 공유 데이터를 액세스하기 위해 설정된 락들을 우선 조사하여야 한다. 공유 데이터에 설정된 락이 모두 읽기 락이라면 읽기 연산은 바로 공유 데이터에 접근할 수 있다. 하지만, 다른 쓰레드가 설정한 락이 쓰기 연산을 위한 배타적 락이라면, 읽기 연산은 배타적 락이 해제될 때까지 기다려야 한다.

Upgrade mutex는 쓰기 연산과 읽기 연산을 위해 3가지 유형의 락을 제공한다.

  • 배타적 락exclusive lock

배타적 락은 일반 mutex와 비숫하다. 임의의 한 쓰레드가 배타적 락을 획득했다면, 다른 쓰레드들은 어떠한 락도 이미 획득된 배타적 락이 해제되지 않는다면 획득할 수 없다. 임의의 쓰레드가 공유 또는 업그레이드 락을 가지고 있다면, 배타적 락을 획득하려는 쓰레드는 블록된다. 배타적 락은 데이터를 수정하기 위한 쓰레드에서 사용한다.

  • 공유 락Sharable lock

임의의 쓰레드가 공유 락을 획득하였다면, 다른 쓰레드들은 공유 또는 업그레이드 락을 획득할 수 있다. 만약 다른 쓰레드가 배타적 락을 가지고 있다면, 공유 락을 획득하기 위해 시도하는 쓰레드는 블록된다. 공유 락은 데이터를 읽기 위한 쓰레드에서 사용된다.

  • 업그레이드 락Upgradable lock

임의의 쓰레드가 업그레이드 락을 획득하였다면, 다른 쓰레드들은 공유 락을 획득할 수 있다. 만약 다른 쓰레드가 배타적 또는 업그레이드 락을 가지고 있다면, 업그레이드 락을 획득하려는 쓰레드는 블록된다. 업그레이드 락은 업그레이드 락을 설정한 쓰레드는 공유 락을 획득한 다른 쓰레드들이 락을 모두 해제하면 자동으로 배타적 락을 획득할 수 있도록 보장해 준다. 업그레이드 락은 일반적으로 쓰레드들이 읽기를 수행하지만, 데이터를 수행하기를 원하는 쓰레드에서 사용할 수 있다. 즉, 쓰기를 수행하는 쓰레드는 업그레이드 락을 사용하고, 읽기를 수행하는 쓰레드는 공유 락을 사용한다. 한가지 주의할 점은 업그레이드 락은 배타적 락과 같이 오로지 한 개의 쓰레드에서만 획득할 수 있다.

상기 세가지 유형의 락을 살펴보면 [리스트 1]의 소스 예제가 설명이 된다. 라인 5에서의 공유 락은 읽기를 수행하는 함수 첫번째 라인에 사용되고, 라인 13의 업그레이드 락은 쓰기를 수행하는 함수의 첫번째 라인에 사용된다. 그러면, 읽기는 쓰기 연산이 없다면 공유 락을 설정하여 여러 개가 수행될 수 있고, 쓰기 연산은 공유 락이 모두 해제 될 때까지 업그레이드 락이 블록된다.

 

다음글 : MongoDB의 락 시스템

 


  • Facebook
  • Twitter
  • Delicious
  • LinkedIn
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS
  1. 아직 댓글이 없습니다.
  1. 엮인글들이 아직 없습니다.