Readers-writer 락

Readers-writer 락(RW Lock)은 읽기만 수행하는 프로세스와 쓰기만 수행하는 프로세스를 분리하는 방식의 동기 처리 기법이다. RW 락은 경쟁 상태가 발생하는 이유는 쓰기 연산 때문이며, 쓰기만 배타적으로 수행하면 문제가 발생하지 않는다는 관찰에 기반한다.

RW 락은 다음 제약을 만족하도록 배타 제어를 수행한다.

  • 락을 획등 중인 reader는 같은 시각에 0개 이상 존재할 수 있다.
  • 락을 획득 중인 writer는 같은 시각에 1개만 존재할 수 있다.
  • reader와 writer는 같은 시각에 락 획득 상태가 될 수 없다.

스핀락 기반 RW 락 구현

void rwloack_read_acquire(int *rcnt, volatile int *wcnt) {
    while (1) {
        while (*wcnt); // writer가 있으면 대기한다.
        __sync_fetch_and_add(rcnt, 1);
        if (*wcnt == 0) { // writer가 없으면 락을 획득한다.
            break;
        }
        __sync_fetch_and_sub(rcnt, 1)
    }
}

void rwlock_read_release(int *rcnt) {
    __sync_fetch_and_sub(rcnt, 1);
}

void rwlock_write_acquire(bool *lock, volatile int *rcnt, int *wcnt) {
    __sync_fetch_and_add(wcnt, 1);
    while (*rcnt); // reader가 있으면 대기한다.
    spinlock_acquire(lock);
}

void rwlock_write_release(bool *lock, int *wcnt) {
    spinlock_release(lock);
    __sync_fetch_and_sub(wcnt, 1);
}
int rcnt = 0;
int wcnt = 0;
bool lock = false;

void reader() {
    while (1) {
        rwlock_read_acquire(&rcnt, &wcnt);
        // critical section (read only)
        rwlock_read_release(&rcnt);
    }
}

void writer() {
    while (1) {
        rwlock_write_acquire(&lock, &rcnt, &wcnt);
        // critical section (write only)
        rwlock_write_release(&lock, &wcnt);
    }
}

러스트에서 RW 락 사용

use std::sync::RwLock;

fn main() {
    let lock = RwLock::new(10);

    {
        // 이뮤터블한 참조(reader)를 얻는다.
        let v1 = lock.read().unwrap();
        let v2 = lock.read().unwrap();
        println!("{} {}", v1, v2); // 읽기 동작
    }

    {
        v = lock.write().unwrap(); // 뮤터블한 참조(writer)를 얻는다.
        *v = 7; // 쓰기 동작
        println!("{}", v); // 읽기 동작
    }
}

이 문서를 인용한 문서