출처 : http://kukuta.tistory.com/35


Read/Write Lock(이하 rwlock)의 기본적인 생각은 아래와 같이 간단하다.

  * Read 작업은 값을 변경하지 않으니 몇개가 붙어도 동기화에 문제가 생기지 않는다.
  * Write 작업은 값을 변경 할 수도 있으니, 하나의 크리티컬 섹션에 하나만 붙어야 한다.
  * Read 작업은 끼리는 여러개가 하나의 크리티컬 섹션에 접근 가능하나, Read하는 것을 도중에 바꾸면 안된다.

 

 위의 세 가지 사항 정도만 제외 한다면 rwlock은 mutex랑 비슷하다. 개념도 비슷하고, 사용법도 비슷하고, 하는
일도 비슷하다.

 rwlock의 장점은 read 작업에 있어서 여러개의 쓰레드가 서로 블록킹 하는 일이 없어 괜한 오버헤드를 가지고 오
지 않고, 단점은
그 특성상 read작업이 많다면 거기에 눌려 write 오퍼레이션은 뒤로 밀리기 마련이다.
 
 write lock을 걸려고 하는 쓰레드가 자원을 못 받아 말라 죽는
시나리오를 만들어 보자.

 1) 1번 쓰레드가 A라는 공유 자원을 참조 하려고 한다.
   *
아직 아무런 lock이 걸려 있지 않으므로 커널은 lock을 허락한다.
 2) 2번 쓰레드가 A라는 공유 자원을 변경 하려고 한다.
   * 변경이라는 것은 wrtie lock을 걸어야 하는데 아직 read 작업이 있으므로 write를 잠시 멈춘다.
     
하지만 그 사이에 다른 read 작업이 또 들어 온다. read 작업은 공유가 되므로 커널은 뒤 늦게 온 read 작업을
     크리티컬섹션 안으로 넣어 버린다. 이런 현상의 반복으로 write를 요청하는 thread는 굶어 죽는 경우가 발생
     해 버릴수 있다.(현실적으로는 이런 경우를 대비하여 만들었 겠지만, 그래도 rwlockmodify작업보
    다는 read가 더 많은 곳에 사용하는 것이 가장  이상적이다
.)


#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict    rwlock, const pthread_rwlockattr_t    *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);


 API가 상당히 직관적이다. mutex같은 것들과 마찬가지로 pthread_rwlock_t 객체를 사용하기 이전에
pthread_rwlock_init으로 객체르르 초기화 해주고, 사용이 끝나고 커널에 반환 해야 할 경우에는 pthread_rwlock_destroy로 객체를 해제해 준다.

 read 작업을 하는 경우에는 pthread_rwlock_rdlock을 호출 하고, write작업을 할경우에는
pthread_rwlock_wrlock을 호출 하면 된다. 그리고 어떠한 read 작업이든, write작업이든 lock을 풀어 줄때는
pthread_rwlock_unlock을 호출 한다. read작업을 다른 말로 shared 작업, 즉 공유가 가능한 작업이라고 하는데 구현상 그 갯수에 제한을 두고 있다.
 
 
Single Unix
계열에서는 아래와 같은 함수를 지원한다..

#include <pthread.h>

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

  try라는 이름과 같이 단시 시도를 할 뿐이다. 만일 lock을 잡을 수 없는 상황이라면 바로 리턴을 한다. 리턴 값은
lock를 잡을 경우에는 0을 리턴하고, 그렇지 못하다면 EBUSY를 리턴한다.

 아래의 예제 코드는 두개의 read lock과 하나의 write lock을 사용한다. 하나의 read lock을 걸고 다른 read lock
를 걸었을 경우 과연 예상대로 lock이 잡히는지 안잡히는지, 그리고 read lock가 걸려 있는 상태에서 write lock는 과연 대기 상태에 있는지를 알아 보고자 하는 코드다.

예제 코드 닫기

#include <pthread.h>
#include <iostream>
#include <unistd.h>

pthread_rwlock_t g_rwLock;
int g_share = 0;

void* thr_readLock(void* arg) {
 int ret = pthread_rwlock_rdlock(&g_rwLock);
 if(ret == 0) {
  std::cout << "try to read lock successfully complete!!" << std::endl;
 }
 sleep(3);
 pthread_rwlock_unlock(&g_rwLock);
 std::cout << "unlock the read lock" << std::endl;
}

void* thr_writeLock(void* arg) {
 int ret = pthread_rwlock_wrlock(&g_rwLock);
 if(ret == 0) {
  std::cout << "try to write lock successfully complete!!" << std::endl;
 }
 pthread_rwlock_unlock(&g_rwLock);
 std::cout << "unlock the write lock" << std::endl;
}

int main() {
 int ret = 0;
 ret = pthread_rwlock_init(&g_rwLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 
 pthread_t readThr[2];
 pthread_t writeThr;

 ret = pthread_create(&readThr[0], NULL, thr_readLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 ret = pthread_create(&readThr[1], NULL, thr_readLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 ret = pthread_create(&writeThr, NULL, thr_writeLock, NULL);
 if(ret != 0) {
  std::cout << strerror(ret) << std::endl;
  exit(1);
 }
 
 sleep(10);
 pthread_rwlock_destroy(&g_rwLock);
}

+ Recent posts