독자-저자 문제
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
독자-저자 문제는 여러 프로세스 또는 스레드가 공유 자원에 동시에 접근할 때 발생하는 동기화 문제이다. 이 문제는 데이터 불일치 가능성을 야기하며, 세마포어 등을 사용하여 해결할 수 있다. 독자 우선, 저자 우선, 기아 방지 등 다양한 종류가 있으며, 각 문제에 따라 독자 또는 저자의 접근 권한에 우선순위를 부여하거나, 기아 상태를 방지하기 위한 해결책을 제시한다.
더 읽어볼만한 페이지
- 병행성 - 세마포어
세마포어는 데이크스트라가 고안한 정수 변수로, P/V 연산을 통해 자원 접근을 제어하고 동기화 문제를 해결하며, 계수 세마포어와 이진 세마포어로 나뉘어 멀티스레드 환경에서 자원 관리 및 스레드 동기화에 기여한다. - 병행성 - 기아 상태
기아 상태는 컴퓨터 과학에서 프로세스가 필요한 자원을 할당받지 못해 무한정 대기하는 현상으로, 단순한 스케줄링 알고리즘, 우선순위 역전, 교착 상태 등으로 인해 발생하며 시스템 효율성을 저하시키고 작업 완료를 지연시키지만, 에이징 기법과 같은 공정한 스케줄링 알고리즘이나 우선순위 조정으로 해결할 수 있다.
독자-저자 문제 | |
---|---|
개요 | |
문제 유형 | 병행성 제어 문제 |
목표 | 공유 자원에 대한 병행 접근 관리 |
설명 | 여러 프로세스 또는 스레드가 공유 자원 (예: 데이터베이스, 파일)에 접근할 때 발생하는 문제로, 독자(reader)는 자원을 읽을 수 있고, 저자(writer)는 자원을 쓸 수 있을 때, 독자와 저자 간의 접근을 어떻게 효율적이고 안전하게 관리할지가 핵심이다. |
문제 정의 | |
독자 | 공유 자원의 내용을 읽기만 하는 프로세스 또는 스레드 |
저자 | 공유 자원의 내용을 수정 (쓰기)하는 프로세스 또는 스레드 |
제약 조건 | 여러 독자는 동시에 공유 자원에 접근할 수 있다. 저자는 공유 자원에 대한 독점적인 접근 권한을 가져야 한다. 즉, 다른 독자나 저자가 동시에 접근할 수 없다. |
해결책 | |
목적 | 데이터 무결성: 저자가 데이터를 쓰는 동안 다른 독자나 저자가 접근하지 못하도록 보장한다. 병행성: 가능한 한 많은 독자가 동시에 자원을 읽을 수 있도록 허용한다. |
일반적인 접근 방식 | 세마포어: 상호 배제 및 자원 접근 제어를 위해 사용 뮤텍스: 상호 배제를 위한 잠금 메커니즘 모니터: 상호 배제 및 조건 변수를 제공 |
우선순위 | 독자 우선: 독자가 항상 저자보다 우선순위를 가진다. 즉, 독자가 대기 중이면 저자는 독자가 모두 읽기를 마칠 때까지 대기한다. (기아 현상 발생 가능) 저자 우선: 저자가 항상 독자보다 우선순위를 가진다. 즉, 저자가 대기 중이면 독자는 저자가 쓰기를 마칠 때까지 대기한다. |
문제점 | |
기아 현상 | 특정 프로세스 (예: 저자)가 자원에 접근하지 못하고 영원히 대기하는 상황 |
데드락 | 둘 이상의 프로세스가 서로 상대방이 점유한 자원을 기다리며 진행하지 못하는 상황 |
예시 | |
데이터베이스 | 여러 사용자가 데이터베이스에서 데이터를 읽고, 관리자는 데이터를 수정하는 경우 |
파일 시스템 | 여러 프로그램이 파일을 읽고, 특정 프로그램은 파일을 수정하는 경우 |
참고 문헌 | |
참고 문헌 | Operating Systems - Design and Implementation, 3rd edition [Chapter: 2.3.2 The Readers and Writers Problem] Synchronization Algorithms and Concurrent Programming |
2. 문제 정의
독자-저자 문제는 여러 프로세스나 스레드가 공유 메모리 영역(임계 구역)과 같은 공유 자원에 동시에 접근하려고 할 때 발생하는 동시성 제어 문제이다. 특히, 최소 하나 이상의 프로세스나 스레드가 데이터를 변경하는 쓰기 작업을 수행할 때 데이터의 일관성이 깨질 위험이 있다.
가장 간단한 해결책은 상호 배제(뮤텍스)를 사용하여 한 번에 하나의 스레드만 공유 자원에 접근하도록 하는 것이다. 하지만 이 방식은 비효율적일 수 있다. 예를 들어, 어떤 스레드(리더)가 데이터를 읽고 있을 때, 다른 리더 스레드가 접근하려고 해도 기다려야 한다. 읽기 작업은 데이터를 변경하지 않으므로 여러 리더가 동시에 읽는 것은 안전함에도 불구하고, 단순한 상호 배제는 이러한 동시성을 허용하지 않아 성능 저하를 일으킬 수 있다.
이러한 비효율성을 개선하고, 읽기 작업의 동시성을 허용하면서도 쓰기 작업의 상호 배제를 보장하기 위한 규칙과 해결책을 다루는 것이 독자-저자 문제의 핵심이다. 문제 해결 과정에서 특정 조건(예: 리더 우선, 라이터 우선, 기아 상태 방지)을 만족시키기 위해 여러 변형된 문제 정의와 해결책이 제시되었다.
- '''첫 번째 독자-저자 문제 (리더 우선)''': 읽기 작업이 진행 중일 때는 새로운 리더를 기다리게 하지 않는다. 이는 라이터의 기아 상태를 유발할 수 있다.
- '''두 번째 독자-저자 문제 (라이터 우선)''': 쓰기 요청이 들어오면 가능한 한 빨리 처리하여 라이터가 불필요하게 오래 기다리지 않도록 한다. 이는 리더의 기아 상태를 유발할 수 있다.[3]
- '''세 번째 독자-저자 문제''': 어떤 스레드(리더 또는 라이터)도 기아 상태에 빠지지 않도록 공정성을 보장한다.
이 문제들은 주로 세마포어 등을 활용하여 해결책을 구현한다.
2. 1. 기본 제약 조건
독자-저자 문제는 공유된 자원(임계 구역)에 여러 프로세스나 스레드가 접근할 때의 동시성 제어 규칙을 다룬다. 기본적인 제약 조건은 다음과 같다.- '''읽기(Read):''' 여러 프로세스나 스레드가 동시에 데이터를 읽는 것이 허용된다. 읽기 작업은 데이터를 변경하지 않으므로 동시 접근이 안전하다.
- '''쓰기(Write):''' 오직 하나의 프로세스나 스레드만이 데이터를 쓸 수 있다. 쓰기 작업 중에는 다른 어떤 스레드(다른 라이터 또는 리더)도 접근할 수 없다.
- '''동시 접근 불가:''' 읽기 작업과 쓰기 작업은 동시에 이루어질 수 없다. 즉, 누군가 데이터를 읽고 있다면 다른 누구도 쓸 수 없고, 누군가 데이터를 쓰고 있다면 다른 누구도 읽거나 쓸 수 없다.
3. 해결 방법
독자-저자 문제를 해결하기 위한 여러 접근 방식이 존재한다. 가장 기본적인 방법은 공유 데이터 영역(임계 구역)을 상호 배제(Mutual Exclusion)를 위한 뮤텍스(Mutex)로 보호하는 것이다. 이 경우, 한 번에 오직 하나의 스레드(독자 또는 저자)만이 데이터에 접근할 수 있다. 하지만 이 방식은 여러 독자가 동시에 데이터를 읽어도 문제가 발생하지 않는다는 독자-저자 문제의 특성을 활용하지 못한다. 예를 들어, 한 독자(`R1`)가 데이터를 읽고 있을 때 다른 독자(`R2`)가 접근을 요청하면, `R1`이 읽기를 마칠 때까지 `R2`가 불필요하게 기다려야 하므로 비효율적이다.
이러한 비효율성을 개선하기 위해, 여러 독자가 동시에 읽는 것을 허용하면서도 저자와의 충돌을 방지하는 동기화 기법이 필요하다. 세마포어(Semaphore)는 이러한 요구사항을 만족시키는 대표적인 해결 도구로 사용된다. 세마포어를 활용하면 독자 간의 동시 접근을 허용하면서 저자의 쓰기 작업 시에는 상호 배제를 보장하는 다양한 알고리즘을 구현할 수 있다. 세마포어를 이용한 구체적인 해결 방법에는 독자에게 우선권을 주는 방식, 저자에게 우선권을 주는 방식, 또는 자원 고갈(Starvation) 문제를 방지하려는 방식 등 여러 가지 접근법이 존재하며, 각각의 장단점을 가진다.
3. 1. 세마포어를 이용한 방법
세마포어(Semaphore)는 공유 자원에 대한 접근을 제어하는 동기화 도구로, 독자-저자 문제를 해결하는 데 사용될 수 있다. 기본적인 아이디어는 뮤텍스(Mutex)와 유사하게 임계 구역(Critical Section)을 보호하는 것이지만, 독자-저자 문제의 특성을 고려하여 여러 독자가 동시에 읽는 것을 허용함으로써 효율성을 높인다. 단순히 뮤텍스만 사용하면 한 번에 하나의 스레드(독자 또는 저자)만 접근할 수 있어 비효율적이다.세마포어를 이용한 해결책은 주로 세 가지 접근 방식으로 나눌 수 있으며, 각각 우선순위 부여 방식과 자원 고갈(Starvation) 문제 발생 가능성에서 차이를 보인다.
- '''첫 번째 독자-저자 문제 (독자 우선)''': 이 방식은 독자에게 우선권을 부여한다. 현재 공유 자원을 읽고 있는 독자가 있다면, 새로 도착한 다른 독자들은 기다리지 않고 즉시 읽기 작업에 참여할 수 있다. 하지만 이 방식은 독자들이 계속해서 도착하는 경우, 저자가 공유 자원에 접근할 기회를 얻지 못하고 무한정 기다리게 되는 저자 기아 상태가 발생할 수 있다.
- '''두 번째 독자-저자 문제 (저자 우선)''': 이 방식은 저자가 쓰기 작업을 요청하면, 가능한 한 빨리 작업을 시작할 수 있도록 보장하는 데 중점을 둔다.[3] 저자가 대기 중일 경우, 새로 도착하는 독자들은 저자가 쓰기 작업을 완료할 때까지 기다려야 한다. 저자의 기아 상태는 방지되지만, 반대로 독자들이 무한정 기다리게 되는 독자 기아 상태를 유발할 수 있다. 이를 위해 저자가 도착하면 추가 세마포어를 사용하여 독자들의 진입을 제어한다.
- '''세 번째 독자-저자 문제 (기아 방지)''': 앞선 두 방식의 기아 상태 문제를 해결하기 위해 제안된 방식으로, 어떤 스레드(독자 또는 저자)도 무한정 대기 상태에 빠지지 않도록 보장하는 것을 목표로 한다. 이를 위해 추가 세마포어를 사용하여 독자와 저자의 요청을 선입선출(FIFO) 순서로 처리함으로써 공정성을 확보하려 한다. 이 방식이 기아 상태를 완전히 방지하기 위해서는 세마포어 자체가 FIFO 방식으로 스레드를 관리해야 한다는 전제 조건이 필요하다.
가장 단순화된 형태로는 두 개의 세마포어만을 사용하여 생산자-소비자 문제의 제한된 버퍼(Bounded-Buffer) 문제와 유사하게 해결하는 방법도 있다. 이 경우, 버퍼 크기만큼의 독자만 동시에 접근할 수 있도록 제한된다.
3. 1. 1. 변수
세마포어 등을 활용하여 문제를 해결할 수 있다.- readcount: 현재 공유 자원(버퍼)에 접근 중인 독자의 수를 나타낸다. (초기값=0)
- wrt: 쓰기(저자) 작업에 대한 상호 배제를 보장하는 세마포어이다. 즉, 한 번에 하나의 저자만 공유 자원에 쓸 수 있도록 한다. (초기값=1)
- mutex: `readcount` 변수에 대한 접근을 상호 배제하여 경쟁 상태를 방지하는 세마포어이다. (초기값=1)
3. 1. 2. 저자 프로세스
세마포어 `wrt`를 사용하여 저자 프로세스를 통제한다. 저자 프로세스는 다음과 같은 단계로 이루어진다.- `wait(wrt)`: 쓰기 작업을 시작하기 전에 `wrt` 세마포어를 획득한다. 이는 다른 저자나 독자가 임계 구역에 접근하는 것을 막고, 쓰기 작업에 대한 상호 배제를 보장하기 위한 과정이다. 임계 구역에 들어가기 위한 허가가 날 때까지 기다린다.
- '''쓰기 작업 수행''': 세마포어를 획득한 후, 공유 데이터에 대한 쓰기 작업을 수행한다. 이 동안 다른 저자나 독자는 접근할 수 없다.
- `signal(wrt)`: 쓰기 작업이 완료되면 `wrt` 세마포어를 반환한다. 이는 임계 구역에서의 작업이 끝났음을 알리고, 다른 대기 중인 프로세스(독자 또는 저자)가 임계 구역에 접근할 수 있도록 허용하는 신호이다.
3. 1. 3. 독자 프로세스
독자 프로세스는 공유 자원에 대한 읽기 작업을 수행한다. 여러 명의 독자가 동시에 데이터를 읽는 것은 허용되지만, 어떤 저자(writer)가 데이터를 쓰고 있는 동안에는 접근할 수 없다. 또한, 독자가 읽고 있는 중에는 저자가 데이터를 쓸 수 없다. 이러한 동기화를 위해 세마포어가 사용된다. 주로 사용되는 변수와 세마포어는 다음과 같다.- '''readcount''': 현재 공유 자원에 접근하여 읽고 있는 독자의 수를 나타내는 변수이다. 초기값은 0이다.
- '''mutex''': `readcount` 변수를 여러 독자 프로세스가 동시에 수정하는 것을 방지하기 위한 세마포어이다. 즉, `readcount` 접근의 원자성을 보장한다. 초기값은 1이다.
- '''wrt''': 저자 프로세스가 공유 자원에 쓰기 작업을 할 수 있는지, 또는 독자 프로세스가 처음으로 접근할 때 저자의 접근을 막기 위해 사용되는 세마포어이다. 초기값은 1이다.
독자 프로세스의 작업 흐름은 다음과 같다.
# '''진입 절차'''
## `wait(mutex)`: `readcount` 변수에 접근하기 전에 다른 프로세스가 접근하지 못하도록 `mutex` 세마포어를 획득한다.
## `readcount` 증가: 현재 읽고 있는 독자의 수를 1 증가시킨다.
## `if readcount == 1` 조건 확인: 만약 자신이 자원에 접근하는 첫 번째 독자라면, 저자의 쓰기 작업을 막아야 한다.
### `wait(wrt)`: 첫 번째 독자일 경우, 저자가 쓰기 작업을 시작하지 못하도록 `wrt` 세마포어를 획득한다. 만약 이미 저자가 `wrt`를 점유하고 쓰고 있다면, 첫 번째 독자는 여기서 대기한다. 이후 도착하는 다른 독자들은 `readcount`가 1보다 크므로 이 단계를 건너뛴다.
## `signal(mutex)`: `readcount` 변수 관련 작업이 끝났으므로, 다른 독자 프로세스가 `readcount`에 접근할 수 있도록 `mutex` 세마포어를 반환한다.
# '''읽기 작업 수행'''
## 공유 자원에 접근하여 필요한 데이터를 읽는다. 이 단계에서는 여러 독자가 동시에 작업을 수행할 수 있다.
# '''종료 절차'''
## `wait(mutex)`: 읽기 작업을 마치고 `readcount` 변수를 수정하기 위해 다시 `mutex` 세마포어를 획득한다.
## `readcount` 감소: 읽기 작업을 마쳤으므로, 현재 읽고 있는 독자의 수를 1 감소시킨다.
## `if readcount == 0` 조건 확인: 만약 자신이 자원을 떠나는 마지막 독자라면, 이제 저자가 쓰기 작업을 할 수 있도록 허용해야 한다.
### `signal(wrt)`: 마지막 독자일 경우, 더 이상 읽는 독자가 없음을 알리고 저자가 자원에 접근할 수 있도록 `wrt` 세마포어를 반환한다.
## `signal(mutex)`: `readcount` 변수 관련 작업이 끝났으므로, `mutex` 세마포어를 반환한다.
이 방식은 '첫 번째 독자-저자 문제' 또는 '독자 우선(readers-preference)' 해결책에 해당한다. 이 해결책에서는 독자가 한 명이라도 읽고 있는 한 새로운 독자는 기다리지 않고 바로 읽기 작업에 참여할 수 있다. 하지만 이로 인해 저자 프로세스가 공유 자원에 접근하지 못하고 무한정 기다리게 되는 기아 상태(starvation)가 발생할 수 있다는 단점이 있다.
4. 읽기-쓰기 문제의 종류
독자-저자 문제는 공유 자원에 대한 동시성 제어 문제 중 하나로, 자원을 읽기만 하는 다수의 독자(Reader)와 자원을 변경하는 소수의 저자(Writer)가 존재할 때 발생한다. 읽기 작업은 동시에 여러 스레드가 수행해도 문제가 없지만, 쓰기 작업은 한 번에 하나의 스레드만 수행해야 하며, 쓰기 작업 중에는 다른 읽기 또는 쓰기 작업이 동시에 이루어져서는 안 된다.
이러한 제약 조건을 만족시키면서 시스템의 효율성을 높이기 위해 다양한 해결책이 제시되었으며, 주로 어떤 스레드에게 우선권을 줄 것인지, 그리고 특정 스레드가 자원에 접근하지 못하고 무한정 기다리는 기아 상태(Starvation)를 어떻게 처리할 것인지에 따라 여러 종류로 나눌 수 있다.
- 첫 번째 독자-저자 문제 (독자 우선): 독자에게 우선권을 부여하여, 읽기 작업 중에는 다른 독자가 기다리지 않도록 한다. 그러나 이 방식은 저자가 기아 상태에 빠질 수 있다.
- 두 번째 독자-저자 문제 (저자 우선): 저자에게 우선권을 부여하여, 저자가 가능한 한 빨리 작업을 시작하도록 보장한다. 이 경우 독자가 기아 상태에 빠질 위험이 있다.
- 세 번째 독자-저자 문제 (기아 방지): 어떤 스레드도 기아 상태에 빠지지 않도록 공정성을 추구한다. 보통 요청 순서대로 처리하는 선입선출(FIFO) 방식의 큐를 활용한다.
각 문제 유형과 해결책에 대한 자세한 내용은 아래 하위 섹션에서 설명한다.
4. 1. 첫 번째 읽기-쓰기 문제 (독자 우선)
공유 자원에 여러 스레드가 동시에 접근해야 할 때, 단순히 상호 배제를 위한 뮤텍스만을 사용하는 것은 비효율적일 수 있다. 예를 들어, 한 독자 스레드(Reader)가 데이터를 읽기 위해 자원을 잠근 상태에서 다른 독자 스레드가 접근을 요청할 경우, 첫 번째 독자가 끝날 때까지 기다리게 하는 것은 불필요하다. 읽기 작업은 데이터를 변경하지 않으므로 여러 독자가 동시에 접근해도 안전하기 때문이다.이러한 배경에서 첫 번째 독자-저자 문제(First Readers-Writers Problem)가 정의된다. 이 문제의 핵심 제약 조건은 "공유 자원이 현재 읽기 작업 중이라면, 다른 독자는 기다리지 않아야 한다"는 것이다. 이는 독자 우선(Readers-Preference) 방식이라고도 불린다.
이 문제를 해결하기 위해 일반적으로 세마포어가 사용된다. 주요 구성 요소는 다음과 같다.
- `resource`: 공유 자원 자체에 대한 접근을 제어하는 세마포어. 저자가 쓰기 작업을 하거나, 첫 번째 독자가 읽기 시작할 때 사용된다.
- `rmutex`: 독자 수를 관리하는 변수(`readcount`)에 대한 접근을 동기화하기 위한 뮤텍스. 독자들이 `readcount`를 동시에 수정하려는 경쟁 상태를 방지한다.
- `readcount`: 현재 공유 자원을 읽고 있는 독자의 수를 나타내는 변수.
작동 방식은 다음과 같다.
1. 저자(Writer): 쓰기 작업을 시작하기 전에 `resource` 세마포어를 획득하여 자원을 잠근다. 쓰기가 끝나면 `resource`를 해제한다. 이를 통해 한 번에 하나의 저자만 쓰거나, 독자가 읽는 동안 저자가 쓰는 것을 방지한다.
2. 독자(Reader):
- 읽기를 시작하기 전에 `rmutex`를 잠그고 `readcount`를 1 증가시킨다.
- 만약 자신이 첫 번째 독자(`readcount`가 1이 됨)라면, `resource` 세마포어를 획득하여 자원을 잠근다. 이는 이후 저자들이 접근하는 것을 막기 위함이다.
- `rmutex`를 해제한다. 이제 다른 독자들이 진입하여 `readcount`를 증가시키고 읽기 작업을 동시에 수행할 수 있다.
- 읽기 작업을 수행한다.
- 읽기가 끝나면 다시 `rmutex`를 잠그고 `readcount`를 1 감소시킨다.
- 만약 자신이 마지막 독자(`readcount`가 0이 됨)라면, `resource` 세마포어를 해제하여 대기 중인 저자가 자원에 접근할 수 있도록 한다.
- `rmutex`를 해제한다.
이 방식에서 `rmutex`는 `readcount` 변수를 보호하여 여러 독자가 동시에 이 변수를 수정하려 할 때 발생하는 경쟁 상태를 막는 중요한 역할을 한다.
그러나 독자 우선 방식에는 단점이 있다. 독자 스레드가 계속해서 도착하는 상황에서는 `readcount`가 0이 될 기회가 좀처럼 오지 않을 수 있다. 이 경우, 저자 스레드는 `resource` 세마포어를 획득하지 못하고 무한정 기다리게 되는 기아 상태에 빠질 수 있다. 즉, 이 해결책은 공정성(fairness)을 보장하지 못한다.
4. 2. 두 번째 읽기-쓰기 문제 (저자 우선)
첫 번째 해결책은 최적이 아니다. 독자 R1이 잠금을 가지고 있고, 저자 W가 잠금을 기다리는 상황에서 다른 독자 R2가 접근을 요청할 수 있다. 이때 R2가 W보다 먼저 자원에 접근하게 되면 저자 W에게 불리할 수 있으며, 이러한 상황이 자주 발생하면 저자 W는 기아 상태에 빠질 수 있다. 따라서 저자 W가 가능한 한 빨리 작업을 시작할 수 있도록 보장하는 방식이 필요하다. 이것이 두 번째 독자-저자 문제의 동기이며, 이 문제의 핵심 제약 조건은 "큐에 추가된 저자는 필요한 것보다 더 오래 기다려서는 안 된다"는 것이다. 이는 저자 우선(Writer Priority) 방식이라고도 불린다.저자 우선 시나리오에 대한 한 가지 해결책은 다음과 같다.[3]
```c
int readcount, writecount; // (초기 값 = 0)
semaphore rmutex, wmutex, readTry, resource; // (초기 값 = 1)
// 독자
reader() {
// 진입 섹션 (ENTRY Section)
readTry.P(); // 독자가 진입을 시도함을 나타냄
rmutex.P(); // 다른 독자와의 경쟁 조건을 피하기 위해 진입 섹션을 잠금
readcount++; // 자신을 독자라고 보고
if (readcount == 1) // 첫 번째 독자인지 확인
resource.P(); // 첫 번째 독자라면 자원을 잠금
rmutex.V(); // 다른 독자를 위해 진입 섹션을 해제
readTry.V(); // 자원에 접근하는 시도가 완료되었음을 나타냄
// 임계 구역 (CRITICAL Section)
// 읽기 수행
// 종료 섹션 (EXIT Section)
rmutex.P(); // 종료 섹션을 예약 (독자 간 경쟁 조건 방지)
readcount--; // 떠나는 것을 나타냄
if (readcount == 0) // 마지막으로 떠나는 독자인지 확인
resource.V(); // 마지막 독자라면 잠긴 자원을 해제
rmutex.V(); // 다른 독자를 위해 종료 섹션을 해제
}
// 저자
writer() {
// 진입 섹션 (ENTRY Section)
wmutex.P(); // 저자를 위해 진입 섹션을 예약 (경쟁 조건 방지)
writecount++; // 진입하는 저자라고 보고
if (writecount == 1) // 첫 번째 저자인지 확인
readTry.P(); // 첫 번째 저자라면 독자들이 진입 시도를 못하게 잠금
wmutex.V(); // 진입 섹션을 해제
resource.P(); // 자원을 예약 (다른 저자가 동시에 쓰는 것을 방지)
// 임계 구역 (CRITICAL Section)
// 쓰기 수행
resource.V(); // 자원 해제
// 종료 섹션 (EXIT Section)
wmutex.P(); // 종료 섹션을 예약
writecount--; // 떠나는 것을 나타냄
if (writecount == 0) // 마지막 저자인지 확인
readTry.V(); // 마지막 저자라면 독자들이 진입 시도를 할 수 있도록 잠금 해제
wmutex.V(); // 종료 섹션을 해제
}
```
이 해결책에서는 저자에게 우선권이 주어진다. 이는 모든 독자가 `readTry` 세마포어를 개별적으로 잠그고 해제하도록 강제하는 방식으로 구현된다. 반면, 저자는 개별적으로 `readTry`를 잠글 필요가 없다. 첫 번째 저자만 `readTry`를 잠그고, 이후의 저자들은 이전 저자가 해제한 `resource` 세마포어를 순차적으로 획득하여 사용한다. 마지막 저자가 떠날 때 `readTry` 세마포어를 해제하여 독자들이 다시 읽기를 시도할 수 있도록 한다.
만약 저자가 이미 `readTry` 세마포어를 잠근 상태라면, 새로운 독자들은 진입 섹션에 들어갈 수 없다. 독자들은 마지막 저자가 `resource`와 `readTry` 세마포어를 모두 해제할 때까지 기다려야 한다. 반대로, 특정 독자가 `readTry` 세마포어를 잠근 상태라면, 이는 대기 중인 저자에게 현재 독자가 진입 섹션에 있음을 알리는 신호가 된다. 따라서 저자는 해당 독자가 `readTry`를 해제할 때까지 기다려야 한다. 독자가 `readTry`를 해제하면, 저자는 즉시 `readTry`를 잠가 이후의 독자들을 차단할 수 있다. 그러나 저자는 현재 임계 구역에서 작업 중인 독자들이 모두 `resource` 사용을 마치고 이를 해제한 후에야 자원에 접근할 수 있다.
`resource` 세마포어는 저자와 독자 모두 진입 섹션에서 잠글 수 있다. 단, `readTry` 세마포어를 먼저 획득해야만 `resource`를 잠글 수 있으며, `readTry`는 한 번에 하나의 프로세스(독자 또는 첫 번째 저자)만 획득할 수 있다.
`rmutex`와 `wmutex` 세마포어는 첫 번째 해결책과 동일한 방식으로 사용된다. 이들의 주된 목적은 여러 독자 또는 여러 저자가 동시에 진입 또는 종료 섹션 코드(카운터 변수 조작 등)를 실행하면서 발생하는 경쟁 조건을 방지하는 것이다.
이 방식은 저자의 작업이 지연되지 않도록 보장하는 데 중점을 두지만, 저자가 계속해서 도착하는 경우 독자들이 자원에 접근하지 못하고 기아 상태에 빠질 수 있는 단점이 있다.
4. 3. 세 번째 읽기-쓰기 문제 (기아 방지)
앞서 설명된 첫 번째와 두 번째 해결책들은 실제로는 기아 상태(starvation)를 유발할 수 있다. 첫 번째 해결책은 작성자(writer)를, 두 번째 해결책은 독자(reader)를 무한정 기다리게 만들 가능성이 있다. 이러한 문제를 해결하기 위해 '''세 번째 독자-작성자 문제'''가 제안되었다. 이 문제의 핵심 제약 조건은 "어떤 스레드도 기아 상태에 빠져서는 안 된다"는 것이다. 즉, 공유 데이터에 대한 잠금을 획득하는 작업은 반드시 유한한 시간 안에 끝나야 함을 의미한다.이 문제에 대한 해결책은 독자와 작성자 모두에게 공정성을 보장하는 것을 목표로 하며, 다음과 같은 방식으로 구현될 수 있다.
int readcount; // 0으로 초기화; 현재 자원에 접근하는 독자 수
// 모든 세마포어는 1로 초기화
semaphore resource; // 자원에 대한 접근(읽기/쓰기)을 제어합니다. 이진 세마포어.
semaphore rmutex; // 공유 변수 readcount에 대한 변경을 동기화합니다.
semaphore serviceQueue; // 공정성: 요청 순서를 유지합니다(신호는 FIFO여야 함)
//독자
reader() {
serviceQueue.P(); // 서비스 받기 위해 대기열에서 대기
rmutex.P(); // readcount에 대한 독점 접근 요청
readcount++; // 활성 독자 수 업데이트
if (readcount == 1) // 내가 첫 번째 독자라면
resource.P(); // 독자를 위해 자원 접근 요청 (작성자 차단)
serviceQueue.V(); // 대기열의 다음 스레드가 서비스 받도록 허용
rmutex.V(); // readcount에 대한 접근 해제
// 읽기 수행
rmutex.P(); // readcount에 대한 독점 접근 요청
readcount--; // 활성 독자 수 업데이트
if (readcount == 0) // 남아있는 독자가 없다면
resource.V(); // 모든 스레드에 자원 접근 해제
rmutex.V(); // readcount에 대한 접근 해제
}
//작성자
writer() {
serviceQueue.P(); // 서비스 받기 위해 대기열에서 대기
resource.P(); // 자원에 대한 독점 접근 요청
serviceQueue.V(); // 대기열의 다음 스레드가 서비스 받도록 허용
// 쓰기 수행
resource.V(); // 다음 독자/작성자에 대한 자원 접근 해제
}
이 해결책의 핵심은 `serviceQueue`라는 세마포어를 사용하는 것이다. 모든 독자와 작성자는 자원에 접근하거나 상태 변수(`readcount`)를 변경하기 전에 이 큐에서 자신의 차례를 기다린다 (`serviceQueue.P()`). 일단 순서가 되어 큐를 통과하면 (`serviceQueue.V()`), 다음 대기 중인 스레드가 서비스를 받을 수 있게 된다.
이 방식은 세마포어가 선입선출(FIFO, First-In, First-Out) 순서, 즉 먼저 요청한 스레드를 먼저 처리하는 방식으로 작동할 때만 기아 상태 방지를 보장할 수 있다. 만약 FIFO 순서가 보장되지 않는다면, 특정 스레드(예: 대기 중인 작성자)가 다른 스레드들에 의해 계속 순서가 밀려 무한정 대기하는 기아 상태가 발생할 수도 있다. 따라서 공정한 순서 보장이 중요하다.
참조
[1]
서적
Operating Systems - Design and Implementation, 3rd edition [Chapter: 2.3.2 The Readers and Writers Problem]
Pearson Education, Inc.
2006
[2]
서적
Synchronization Algorithms and Concurrent Programming
Pearson Education
[3]
간행물
Concurrent Control with "Readers" and "Writers"
http://cs.nyu.edu/~l[...]
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com