참고 자료 : 혼자 공부하는 컴퓨터구조 + 운영체제
사진 출처 : Operating System Concepts 10E
1. 동기화란
개요
- 프로세스와 스레드는 동시 다발적으로 동작한다.
- 자원의 일관성을 위해 프로세스와 스레드의 동기화 필요
<동기화의 의미>
1. 개요
- 공동의 목적을 위해 동시에 수행되는 프로세스들은
- 올바른 수행을 위해 동기화되어야 한다.
2. 프로세스의 동기화
- 프로세스(스레드)들의 수행 시기를 맞추는 것
- 실행 순서 제어
- 상호 배제
- 동시에 접근해서는 안되는 자원에 하나의 프로세스만 접근하게 하기
<동기화 예시>
1. 실행 순서 제어를 위한 동기화
- Reader Writer Problem
- 실행의 순서 지켜야함!
- reader 프로세스는 파일 안에 값이 존재한다는 특정 조건이 만족되어야 실행 가능
- writer의 조건이 먼저 선행되어야 함
2. 상호 배제를 위한 동기화
예시 1) Bank Account Problem
- 공유가 불가능한 자원의 동시 사용을 피하기 위한 동기화
- 예시
- 문제가 되는 상황은 (처음 잔액 10만원)
- 프로세스 A 진행 도중, 저장이 되기 전 context swtich 발생하고 (10만원)
- 프로세스 B도 저장이 되기 전까지 진행 후 context swtich 되어 (10만원)
- 프로세스 A의 값 저장 (12만원)
- 프로세스 B의 값 저장 한 상황 (15만원)
- 결과적으로 17만원이 아닌 15만원이 잔액이 된다.
- 문제를 막으려면
- 한 번에 하나의 프로세스만 접근해야 하는 자원에 동시 접근을 막기
- 프로세스 A가 다 끝난 후에 프로세스 B 실행
예시 2) Producer & Consumer Problem
producer and consumer c++ code
- Producer: 물건을 계속해서 생산하는 생산자
- Consumer: 물건을 계속해서 소비하는 소비자
- 총합: 공유 자원
총합 = 10 //전역변수
Producer()
{
//버퍼에 데이터 삽입
//총합 변수 1 증가
}
Consumer()
{
//버퍼에서 데이터 꺼내기
//총합 변수 1 감소
}
- 이러한 상태에서 생산자와 소비자를 각각 100,000 실행하면?
- 0과는 다른 값이 되거나, 오류가 발생하기도 한다.
- 이유는?
- 동기화가 되지 않았기 때문에 발생한 문제
- 동시에 접근해서는 안되는 자원(공유자원)에 동시에 접근한 결과
<공유 자원과 임계 구역>
1. 공유 자원 (Shared Resource)
- 여러 프로세스 혹은 스레드가 공유하는 자원
- ex)
2. 임계 구역 (Critical Section)
- 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역
- 임계 구역에 진입하고자 하면, 진입한 프로세스 이외에는 대기해야 한다.
- 프로세스 A가 실행중이면, 프로세스 B는 A가 끝날 때까지 대기했다가 실행
- ex)
3. Race Condition
- 임계구역에 동시에 접근하여 자원의 일관성이 깨지는 상태
4. 운영체제가 임계구역 문제를 해결하는 세가지 원칙
- 상호 배제 (mutual exclusion)
- 한 프로세스가 critical section에 진입했다면 다른 프로세스는 들어올 수 없다.
- 진행 (progress)
- critical section에 어떤 프로세스도 진입하지 않았다면, 진입하고자 하는 프로세스는 들어갈 수 있어야 한다.
- 유한 대기 (bounded waiting)
- 한 프로세스가 critical section에 진입하고 싶다면, 언젠가는 critical section에 들어올 수 있어야 한다.
2. 동기화 기법
<뮤텍스락 (Mutex Lock)>
mutex lock C++ code
1. 개요
- 상호 배제를 위한 동기화 도구 (자물쇠 역할)
- ex) 탈의실(임계구역)에 들어가는 손님(프로세스), 탈의실을 잠그는 자물쇠(뮤텍스락)
2. 뮤텍스락
- 코드로 구현해 보기
- 전역변수 하나와 함수 두 개로 구현 가능
- 전역 변수 lock
- acquire 함수
- 임계구역을 잠그는 역할
- 프로세스가 임계 구역에 진입하기 전에 호출
- 임계구역이 잠겨 있다면, 열릴 때 까지 계속 체크
- 임계구역이 열려 있다면, 임계구역을 잠그기
- release 함수
- 임계 구역의 잠금을 해제하는 역할
- 임계 구역에서의 작업이 끝나고 호출
- 현재 잠긴 임계 구역을 열기
- 예시
acquire()
{
while(lock == true) //잠겨있다면,
; //임계구역이 잠겨있는지 계속 확인
lock = true; //lock == false인 경우 임계구역 진입 후 lock을 다시 true로 만들기
}
release()
{
lock = false; // 임계구역 작업 끝났으니 lock 해제
}
3. Busy Waiting
while(lock == true) ;
- 무한히 대기하면서 임계구역을 체크하는 것 -> 좋은 방식은 아니다.
<세마포 (Semaphore)>
semaphore c++ code
1. 개요
- 뮤텍스락 보다 일반화된 방식의 동기화 도구
- 공유 자원이 여러개 있는 경우에도 작용 가능
- 상호 배제와 실행 순서 동기화 수행 가능
- ex) 이진 세마포, 카운팅 세마포
2. 카운팅 세마포
- 임계 구역 앞에서 멈춤 신호를 받으면 잠시 기다리기
- 임계 구역 앞에서 가도 좋다는 신호를 받으면 임계 구역 진입
- 코드로 구현해 보기
- 전역변수 하나, 함수 두 개로 구현가능
- 전역변수 S
- 임계 구역에 진입할 수 있는 프로세스의 갯수
- 다른 말로 하면 사용 가능한 공유 자원의 갯수
- wait 함수
- 임계구역에 들어가도 좋은지, 기다려야 할지를 알려주는 함수
- signal 함수
- 임계구역 앞에서 기다리는 프로세스에 '이제 가도 좋다' 라고 신호를 주는 함수
- 예시
wait()
{
while(S<=0) //임계 구역에 진입 못하면
; //진입 가능한 자원 있을때 까지 확인
S--; //진입할 수 있다면, S하나 감소시키고 임계구역 진입
}
signal()
{
S++; //임계구역에서 작업을 마친 뒤 S를 1증가
}
3. 문제점과 해결 방안
- 문제점
- 세마포 방식 또한 busy waiting을 한다
- CPU 사이클의 낭비!
- 해결 방법
- 사용할 수 있는 자원이 없을 경우 대기 상태로 만든다.
(해당 프로세스의 PCB를 대기 큐에 삽입)
- 사용할 수 있는 자원이 생긴 경우, 대기 큐의 프로세스를 준비 상태로 만듦
(해당 프로세스의 PCB를 대기 큐에서 꺼내 준비 큐에 삽입)
- 코드 예시
wait()
{
S--;
if(S<0)
{
add this process to Queue; //PCB를 대기큐에 삽입
sleep(); //대기 상태
}
}
signal()
{
S++;
if(S<=0)
{
remove a process p from Queue; //대기 상태에 있는 프로세스 제거
wakeup(p); //프로세스 p를 대기 상태에서 준비 상태로 만들기
}
}
4. 세마포의 실행 순서 동기화
- 예시
- 변수 S를 0으로 두고
- 먼저 실행할 프로세스 뒤에 signal 함수
- 다음에 실행할 프로세스 앞에 wait 함수를 붙이기
- 동작 순서
- process1이 임계 구역 들어가서 실행 후 종료하면, siganl 함수를 통해 S가 1이 되고,
- process2가 S가 1인 것을 확인 후 실행
- 결론적으로 p1 이 p2보다 먼저 실행된다.
<모니터>
1. 개요
- 매번 임계구역 앞 뒤로 wait(), signal() 호출하는 것이 번거롭다.
- 아래의 이유들 때문에 실수 유발 가능
- 세마포 누락
- 함수 순서 바꿈
- 함수 중복 사용
- etc
- 상호 배제와 실행 순서 동기화 수행 가능
- 모니터 안에는 하나의 프로세스만 있을 수 있다.
2. 모니터의 상호 배제
- 인터페이스를 위한 큐
- 공유자원에 접근하고자 하는 프로세스를 큐에 삽입
- 큐에 삽입된 순서대로 공유 자원 이용
3. 모니터의 실행 순서 제어를 위한 동기화
- 코드를 만든다면
- 조건 변수 이용
- 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수
- 조건변수에 대한 큐가 존재 (아래 그림의 빨간 네모칸)
- 조건변수.wait()
- 대기 상태로 변경, 조건 변수에 대한 큐에 삽입
- 조건변수.signal()
- wait()으로 대기 상태로 접어든 조건변수를 실행 상태로 변경
- 실행 순서 제어를 위한 동기화의 핵심!
- 특정 프로세스가 아직 실행될 조건이 되지 않았을 때에는 wait을 통해 실행을 중단한다.
- 특정 프로세스가 실행될 조건이 충족되었을 때에는 signal을 통해 재개한다.
4. 모니터의 구조