비동기 학습 때 자원의 일관성을 위해 필요하다고 한 "동기화"에 대해 알아보자.
: 자원의 일관성을 보장하기 위해 프로세스들의 수행 시기를 맞추는 것.
: 실행의 문맥을 갖는 모든 대상은 동기화 대상이기에 스레드도 동기화 대상이다.
동시다발적으로 실행되는 프로세스들은 서로 협력하며 영향을 주고 받는다.
이 과정에서 자원의 일관성을 보장해야 한다.
이를 위해 동기화는 아래와 같이 2가지가 이루어진다.
Writer라는 값을 저장하는 프로세스와 Reader라는 저장된 값을 읽는 프로세스가 있다고 했을 때,
두 프로세스는 무작정 실행되서는 안된다.
실행의 순서가 있기 때문이다. Reader는 저장된 값이 존재한다는 조건이 만족 되어야만 한다.
공유가 불가능한 자원의 동시 사용을 피하기 위한 동기화이며
한 번에 하나의 프로세스만 접근해야 하는 자원에 동시 접근을 막기 위함을 의미한다.
ex) 프린터 : 한 번에 하나씩만 작업이 가능하다.
ex) Bank account problem : 계좌의 접근이 동시적으로 일어나면 잔액이 중첩되서 예상 못한 결과가 나올 수 있다.
공동으로 이용하는 변수, 파일, 장치 등의 자원을 공유 자원이라 하고,
공유 자원에 접근하는 코드 중 동시에 실행하면 문제가 발생하는 코드 영역을 임계 구역이라 한다.
공유 자원 : 여러 프로세스 혹은 스레드가 공유하는 자원
ex) 전역 변수, 파일, 입출력장치, 보조기억장지 등
임계 구역 : 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역
ex) 총합 변수, 잔액 변수
임계 구역에 진입하고자 하면 진입한 프로세스 이외에는 대기해야 한다.
임계 구역에 동시에 접근하면 자원의 일관성이 깨질 수 있다.
이를 레이스 컨디션(race condition)이라 한다.
: 상호 배제를 위한 동기화 도구 ex) 자물쇠 역할
let lock = boolean;
acquire() {
while (lock === true) { // 임계구역이 잠겨있다면
~ // 임계구역이 잠겨있는지 반복적으로 확인 (busy waiting)
}
lock = true; // 임계구역이 잠겨 있지 않다면 임계구역 잠금
}
release() {
lock = false; // 임계구역 작업이 끝났으니 잠금 해제
}
acquire 함수
release 함수
단점 : (계속 체크하면서 무한히 기다리는) Busy Waiting 이 적용된다. CPU 낭비
: 일반화된 방식의 동기화 도구
: 공유 자원이 여러 개 있는 경우`에도 적용 가능한 동기화 기법
: 임계 구역 앞에서 멈춤 신호를 받으면 대기, 가도 좋다는 신호를 받으면 임계 구역 진입.
var S = // 임계 구역에 진입할 수 있는 프로세스의 개수(사용 가능한 공유 자원의 수)의 전역 변수S
wait() // 입계 구역 진입 가능 여부 "OK" or "NOPE" 를 알려주는 wait 함수
// 입계 구역
signal() // 입계 구역 진입을 기다리던 프로세스에게 "OK" 신호를 주는 signal 함수
// ex)
wait() {
while (S <= 0) // 임계 구역에 진입할 수 있는 프로세스 개수가 0 이하라면
; // 사용할 수 있는 자원이 있는지 무한반복 (Busy Waiting)
S--; // 임계 구역에 진입할 수 있는 프로세스가 1개 이상면 S 감소하고 진입
}
signal() {
S++ // 임계 구역에서의 작업을 마치고 S 증가 (내가 빠져나감)
}
: 뮤덱스 락처럼 Busy Waiting이 적용된다.
: 세마포는 상보 배제 동기화 + 실행 순서 동기화가 가능하다.
P1
// 임계 구역
signal()
P2
Wait()
// 임계 구역
// P1이 먼저 실행되면 바로 들어간다.
// P2가 먼저 실행되면 Wait(대기)로 들어가서 P1이 먼저 들어간다.
단점 : 세마포는 임계구역 앞위로 wait(), signal()을 매번 호출해야해서 불편한다.
(프로젝트가 커질수록 누락, 순서의 뒤바낌 등 문제발생 가능성이이 커진다)
: 개발자가 사용하기 편리한 도구
: 상호 배제와 실행 순서 동기화 모두를 제공하는 동기화 기법
상호 배제
- 인터페이스를 위한 큐
- 공규 자원에 접근하고자 하는 프로세스를 (인터페이스를 위한) 큐에 삽입
- 큐에 삽입된 순서대로 공유 자원 이용
실행 순서 제어
- 조건 변수(프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 변수) 이용한다.
- 특정 프로세스가 아직 실행될 조건이 되지 않았을 때는 wait를 통해 실행을 중단.
- 특정 프로세스가 실행될 조건이 충족되었을 때에는 signal로 재개.
일어나지 않을 일을 계속 기다리면서 동작이 멈추는 상태
일반적인 자원할당 그래프
교착상태가 발생된 자원할당 그래프는 원의 형태를 가진다.
위 네 가지 조건 중 하나라도 만족하지 않으면 교착 상태가 발생하지 않는다.
위 네 가지 조건을 모두 만족하면 교착상태가 발생할 수 있다.
: 교착 상태 발생 4가지 조건 중 하나를 없애는 방법
교착 상태 예방 방법은 교착 상태 방지가 가능하나 부작용이 따른다.
: 교착 상태를 무분별한 자원 할당으로 인해 발생 했다고 간주
: 교착 상태가 발생하지 않을 만큼 조심히 할당하는 방법
: 배분할 수 있는 자원의 양을 교착 상태가 발생되지 않도록 조절
: 교착 상태 발생 후 조치
: 프로세스가 자원을 요구하면 일단 항당하고 교착 상태가 발생하면 회복 시킨다.
선점을 통한 회복
- 교착 상태가 해결될 때까지 한 프로세스씩 자원을 몰아준다.
프로세스 강제 종료를 통한 회복
- 교착 상태 프로세스 모두 강제 종료(내역 상실)
- 교착 상태 해결될 때까지 한 프로세스씩 강제 종료