pthread_rwlock_t: 읽기/쓰기 락 (Read-Write Lock)
개념
- 읽기 작업은 동시에 여러 개 가능,
쓰기 작업은 오직 하나만 가능하도록 제어하는 락. - 다수의 reader는 동시에 접근 가능
- 단 하나의 writer만 접근 가능하고, 이 동안 reader도 접근 불가
- 읽기 작업이 많은 경우 성능 향상 가능.
핵심 동작 원리
락 요청 | 허용 조건 |
읽기 락 | 쓰기 락이 잡혀 있지 않으면 여러 개 허용 |
쓰기 락 | 아무도 락을 잡고 있지 않아야 허용 (reader, writer 모두 없어야 함) |
관련 함수 (POSIX Threads)
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
pthread_rwlock_init(&rwlock, NULL);
pthread_rwlock_rdlock(&rwlock); // 읽기 락
pthread_rwlock_wrlock(&rwlock); // 쓰기 락
pthread_rwlock_unlock(&rwlock); // 락 해제
pthread_rwlock_destroy(&rwlock);
1. 선언 및 초기화
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
혹은 수동 초기화:
pthread_rwlock_t rwlock;
pthread_rwlock_init(&rwlock, NULL);
- 읽기-쓰기 락을 초기화한다.
- rwlock: 초기화할 pthread_rwlock_t 객체의 포인터
- attr: 락 속성 (보통 NULL 사용하여 기본 속성으로 설정)
반환값
- 0: 성공
- EINVAL: 속성이 유효하지 않음
- ENOMEM: 메모리 부족
2. 읽기 락 (공유 락)
pthread_rwlock_rdlock(&rwlock);
- 읽기 락을 획득
- 다른 읽기 락과는 공존 가능
- 쓰기 락이 있으면 대기
내부적으로는 다음과 같은 일을 함
- 쓰기 락이 존재하는지 검사
- 없으면 읽기 락 획득 (락 카운터 증가)
- 있으면 대기열에 들어가 블로킹
반환값
- 0: 성공
- EINVAL: 락이 유효하지 않음
- EDEADLK: 동일 쓰레드가 이미 락을 보유 중일 때 (POSIX 일부 구현에서는 허용 안 함)
3. 쓰기 락 (배타 락)
pthread_rwlock_wrlock(&rwlock);
- 쓰기 락을 획득
- 읽기/쓰기 락 모두 없어야 통과
- 단 하나의 쓰레드만 쓰기 락을 가질 수 있음
내부 동작
- 읽기 락, 쓰기 락 모두 없는 상태여야 함
- 두 조건이 충족되면 쓰기 락 획득
- 쓰기 락이 잡히면 reader와 writer 모두 대기
반환값
- 0: 성공
- EINVAL: 락이 유효하지 않음
- EDEADLK: 동일 쓰레드가 이미 락을 보유 중일 때 (POSIX 일부 구현에서는 허용 안 함)
4. 비차단 읽기 락
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
- 비차단(non-blocking) 읽기 락 시도
- 즉시 성공하거나 EBUSY를 리턴한다.
반환값
- 0: 성공
- EBUSY: 이미 쓰기 락이 걸려있어서 실패
- EINVAL: 락이 유효하지 않음
5. 비차단 쓰기 락
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
- 비차단 쓰기 락 시도
- 락이 사용 중이면 즉시 EBUSY를 리턴하고 대기하지 않음
반환값
- 0: 성공
- EBUSY: 이미 누군가 읽거나 쓰고 있음
- EINVAL: 유효하지 않은 락 객체
6. 락 해제
pthread_rwlock_unlock(&rwlock);
- 읽기 락 또는 쓰기 락을 해제
- 어떤 락이 걸려 있는지에 따라 내부 처리 방식이 다름
내부 동작
- 읽기 락인 경우: 읽기 락 카운터 감소
- 쓰기 락인 경우: 락 완전 해제
- 마지막 unlock이 되면 대기 중인 쓰레드들에게 wake-up
반환값
- 0: 성공
- EINVAL: 락 객체가 유효하지 않음
- EPERM: 락을 보유한 쓰레드가 아님 (특히 쓰기 락의 경우 중요)
7. 파괴
pthread_rwlock_destroy(&rwlock);
- 락 객체를 파괴하고, 관련 자원을 해제한다.
- 락이 사용 중일 경우 파괴하면 안 됨
반환값
- 0: 성공
- EBUSY: 아직 락이 걸려 있거나, 대기 중인 쓰레드가 있음
- EINVAL: 잘못된 객체
예제 코드
#include <stdio.h>
#include <pthread.h>
int shared_data = 0;
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
void* reader(void* arg) {
pthread_rwlock_rdlock(&rwlock);
printf("Reader read: %d\n", shared_data);
pthread_rwlock_unlock(&rwlock);
return NULL;
}
void* writer(void* arg) {
pthread_rwlock_wrlock(&rwlock);
shared_data++;
printf("Writer wrote: %d\n", shared_data);
pthread_rwlock_unlock(&rwlock);
return NULL;
}
int main() {
pthread_t t1, t2, t3;
pthread_create(&t1, NULL, reader, NULL);
pthread_create(&t2, NULL, writer, NULL);
pthread_create(&t3, NULL, reader, NULL);
pthread_join(t1, NULL);
pthread_join(t2, NULL);
pthread_join(t3, NULL);
pthread_rwlock_destroy(&rwlock);
return 0;
}
'Deep Dive > CS' 카테고리의 다른 글
[CS] HTTP (요청/응답, 헤더, 메소드, 상태코드, HEAD 메소드) (0) | 2025.05.05 |
---|---|
[CS] OSI 7계층 모델 (0) | 2025.05.04 |
[Deep Dive] 쓰레드와 병렬 프로그래밍 - 3탄 동기화 기법 조건 변수 (Condition Variable) (0) | 2025.05.03 |
[Deep Dive] 쓰레드와 병렬 프로그래밍 - 2탄 동기화 기법 Mutex (0) | 2025.05.03 |
[Deep Dive] 쓰레드와 병렬 프로그래밍 - 1탄 개념 이해 (0) | 2025.05.03 |