empty
와 buffer full
을 구별할 수 없는 문제가 발생한다. 이에 대한 해결책으로BUFFER_SIZE-1
만큼 사용 가능하도록 하여 문제를 해결한다.하지만, 카운터를 사용했을 때도 경쟁상태로 인한 공용데이터 값의 불일치 문제가 발생하게 된다.
counter++ 연산
register1 = counter // 현재 카운터 값을 레지스터에 넣고
register1 = register1 + 1 // 레지스터 값에 1을 더한다음에 다시 레지스터 값에 넣어 저장
counter = register1 // 카운터 값을 변경
counter-- 연산
register1 = counter // 현재 카운터 값을 레지스터에 넣고
register1 = register1 - 1 // 레지스터 값에 1을 뺀다음에 다시 레지스터 값에 넣어 저장
counter = register1 // 카운터 값을 변경
S0: producer execute register1 = counter {register1 = 5} // register1 = 5
S1: producer execute register1 = register1 + 1 {register1 = 6} // register1 = 6, 아직 counter 변수 저장 x
S2: consumer execute register2 = counter {register2 = 5} // register2 = 5
S3: consumer execute register2 = register2 – 1 {register2 = 4} // register2 = 4, 아직 counter 변수 저장 x
S4: producer execute counter = register1 {counter = 6 } // counter = 6
S5: consumer execute counter = register2 {counter = 4} // counter = 4
- 위 코드에서 살펴봤듯, 공유 자원 접근 순서에 따라 실행 결과가 달라진다는 것을 확인했다.
- 그럼 임계 영역 문제를 어떻게 해결할 수 있을까?
➡️ 임계 구역의 동시 접근을 해결하기 위해 Lock(잠금), peterson’s Algorithms(피터슨 알고리즘), Semaphore(세마포어) 와 같은 방법이 있다.
프로세스 2개가 경쟁하는 상황에서 사용되는 솔루션이다. (두 개의 프로세스만 비교 가능하다는 한계 존재)
flag[0]=true
: P0(프로세스0)이 임계 구역에 들어갈 준비가 되었음을 의미flag[1]=true
: P1(프로세스1)이 임계 구역에 들어갈 준비가 되었음을 의미 flag[0] = false // false은 임계 구역 사용을 원하지 않음을 뜻함.
flag[1] = true
turn = 0 // 0 은 0번 프로세스를 가리킴, 1은 1번 프로세스를 가리킴
예시 1 ⭐⭐
P0: flag[0] = true // 임계 구역 사용을 원함
turn = 1 // 1번 프로세스에게 차례가 감
while( flag[1] && turn == 1 )
{
// flag[1] 이 turn[1] 을 가지고 있으므로 현재 사용중임
// 임계 구역이 사용 가능한지 계속 확인
}// 임계 구역
...
// 임계 구역의 끝
flag[0] = false // 사용 완료시 false로 바꿔준다.
P1: flag[1] = true // 임계 구역 사용을 원함
turn = 0 // 0번 프로세스에게 차례가 감
while( flag[0] && turn == 0 )
{
// 임계 구역이 사용 가능한지 계속 확인
}// 임계 구역
...
// 임계 구역의 끝
flag[1] = false // 사용 완료시 false로 바꿔준다.
예시 2 ⭐⭐
Pi: flag[i] = true // 임계 구역 사용을 원함
turn = j // j번 프로세스에게 차례가 감
while( flag[j] && turn == j )
{
// flag[j] 이 turn[j] 을 가지고 있으므로 현재 사용중임
// 임계 구역이 사용 가능한지 계속 확인
}// 임계 구역
...
// 임계 구역의 끝
flag[i] = false // 사용 완료시 false로 바꿔준다.
Pi: flag[j] = true // 임계 구역 사용을 원함
turn = i // i번 프로세스에게 차례가 감
while( flag[i] && turn == i )
{
// flag[j] 이 turn[j] 을 가지고 있으므로 현재 사용중임
// 임계 구역이 사용 가능한지 계속 확인
}// 임계 구역
...
// 임계 구역의 끝
flag[j] = false // 사용 완료시 false로 바꿔준다.
- 위에서 살펴본 피터슨 알고리즘과 같은 S/W 해결방법에는 한계가 있기 때문에, H/W 방법을 사용한다.
- Locking 기법으로 CS문제를 해결해야 한다. ⇒ H/W적 해결을 해야한다.
acquire lock
release lock
do{
acquire lock // lock을 얻는 부분 - CS영역에 진입가능
critical section
release lock // lock을 반환하는 부분 - CS 실행 완료 시, lock을 돌려준다.
remainder section
} while (TRUE);
acquire()
: lock 획득release()
: lock 반환개념
문제점
- sleep wating 방식
대기 큐를 사용하여 사용 가능한 자원이 생기면 진입을 허가하는 방식
- Busy Waiting (=spin lock) 방식
우선순위가 가장 높은 프로세스 A, 중간인 B, 가장 낮은 C가 존재할 때,
프로세스A가 CS 영역을 사용하고자 할 때, 프로세스 C가 CS 영역을 이미 사용 중이라면, 프로세스 C가 lock을 걸어 놨기 때문에 프로세스A는 우선순위가 높더라도 대기 상태에 들어가야한다.
이 타이밍에 공유자원을 필요로 하지 않는 B가 작업을 수행하기 위해서 오게 된다. B는 C보다 우선순위가 더 높은 프로세스이고 공유자원 또한 필요로 하지 않는 프로세스 이기 때문에 C는 하던 작업을 멈추고 B에게 CPU를 내어주게 된다.
➡️ 이렇듯, 상대적으로 우선순위가 가장 높은 프로세스인 'A'가 마치 우선순위가 가장 낮은 프로세스처럼 실행이 되는 현상인 우선순위 역전이 일어나게 된다.
➡️ 즉, 공유자원에 대한 lock에 대한 개념 때문에 발생하는 현상이다.
우선순위 역전 문제 해결 방법 : 우선순위 상속