반효경 교수님의 운영체제 강의를 참고하였습니다.

(https://core.ewha.ac.kr/publicview/C0101020140318134023355997?vmode=f)

프로그램적 해결법의 충족조건

  • Mutual Exclusion(상호 배제)
    • 프로세스 Pi가 critical section 부분을 수행 중이면 다른 모든 프로세스들은 그들의 critical section에 들어가면 안 된다
  • Progress(진행)
    • 아무도 critical section에 있지 않은 상태에서 critical section에 들어가고자 하는 프로세스가 있으면 critical section에 들어가게 해주어야 한다.
  • Bounded Waiting(유한 대기)
    • 프로세스가 critical section에 들어가려고 요청한 후부터 그 요청이 허용될 때까지 프로세스들이 critical section에 들어가는 횟수에 한계가 있어야 한다.
    • ex) 프로세스 3개중 2개가 번갈아가면서 접근하고 1개는 계속 기다리는 경우

Algorithm 1

  • Synchronization variable
    • turn = 0 → Pi can enter its critical section if(turn == i)
    • turn이 0이라는 의미는 0번째 프로세스가 critical section에 접근할 수 있다는 의미
  • P0의 경우
do {
	while(turn != 0);  // waiting
	critical section
	turn = 1;          // change turn
	remainder section
} while(1);
  • Mutual Exclusion은 충족되나, Progress는 되지 않음, 극단적인 경우 P0는 빈번하고 P1는 1번만 들어갈 경우 P0는 영원히 들어가지 못함.

Algorithm 2

  • Synchronization variables
    • boolean flag[2];
    • initial flag = false
    • Pi ready to enter its critical section
  • Process Pi
do {
	flag[i] = true;
	while(flag[j]);
	critical section
	flag[i] = false;
	remainder section
} while(1);
  • 둘 다 2행까지 수행 후 끊임없이 대기하는 상태 발생
  • Mutual

Algorithm 3(Peterson’s Algorithm)

  • algorithm 1과 algorithm 2를 합쳐 놓음
do {
	flag[i] = true;
	//i번째 프로세스가 임계구역에 들어가고 싶다는 것을 알림

	turn = j;
	//i번째 프로세스가 선언한 다음 j차례로 돌려줌으로써
	//내가 쓰기 전에 먼저 접근하고 싶은 프로세스가 있는지 확인

	while(flag[j] && turn == j); // 내 차례거나 상대방
	//critical section에 접근하기 위해서는 나 외에 다른 프로세스가 기다리지 말거나
	//flag[j]=false 즉, 내 차례여야 한다.

	critical section;
	flag[i] = false;
	remainder section
} while(1)
  • 3가지 조건 다 만족
  • Busy waiting(=spin lock) = CPU와 memory를 계속 사용하면서 wait

Semaphore

  • S
    • integer variable : 공유 자원의 갯수

    • P(S)

      • critical section 값을 획득하는 과정
      while(S<=0) do no-operation; //busy waiting
      S--;
      
    • V(S)

      • 반납하는 과정
      S++;
      
    • S, V연산은 atomic 하다고 가정을 하는 것

번외로 P와 V연산의 의미는 세마포어를 개발한 다익스트라가 네덜란드어인 Probeer와 Verhoog에서 따왔다고 한다.

Critical section of n processes

  • 컴퓨터가 S, V연산을 지원해 준다면
semaphore mutex;
do {
	P(mutex);
	critical section
	V(mutex);
	remainder section
while(1);
  • busy-wait는 효율적이지 못함(=spin lock)
  • Block & Wake up 방식의 구현이 있음(=sleep lock)
  • 컴퓨터가 P, V연산을 지원하면 피터슨 알고리즘 같이 구현할 atomic한 것을 신경쓰지 않아도 됨

Block / Wakeup Implementation

  • 세마포어를 다음과 같이 정의
typedef struct {
	int value;             /* semaphore*/
	struct process *L;     /* process wait queue */
} semaphore;

https://user-images.githubusercontent.com/28971015/116872706-526aee00-ac51-11eb-9973-e0e1d56b6d89.png

  • block과 wakeup을 다음과 같이 가정
    • block
      • 커널은 block을 호출한 프로세스를 suspend시킴
      • 이 프로세스의 PCB를 semaphore에 대한 wait queue에 넣음
    • wakeup(P)
      • block된 프로세스 P를 wakeup 시킴
      • 이 프로세스의 PCB를 ready queue로 옮김
P(S):
	S.value--;                   /* prepare to enter */
	if(S.value < 0) {
		add this process to S.L;
		block();
	}

V(S):
	S.value++;
	if(S.value <= 0) { // value <= 0이 자원을 기다리는 프로세스가 있음을 의미 P(S)에서 value--
		remove a process P from S.L;
		wakeup(P);
	}

Two Types of Semaphore

  • Counting semaphore
    • 도메인이 0이상인 임의의 정수값
    • 주로 resource counting에 사용
  • Binary semaphore(=mutex)
    • 0 또는 1 값만 가질 수 있는 semaphore
    • 주로 mutual exclusion(lock/unlock)에 사용

Deadlock and Starvation

  • Deadlock
    • 둘 이상의 프로세스가 서로 상대방에 의해 충족될 수 있는 event를 무한히 기다리는 현상
  • Starvation
    • indefinite locking, 프로세스가 suspend된 이유에 해당하는 세마포어에 큐에서 빠져나갈 수 없는 현상

Monitor

  • Semaphore의 문제점
    • 코딩하기 힘들다
    • 정확성(correctness)의 입증이 어려움
    • 자발적 협력(voluntary cooperation)이 필요함
    • 한번의 실수가 모든 시스템에 치명적 영향
  • 동시 수행중인 프로세스 사이에서 abstract data type의 안전한 공유를 보장하기 위한 high-level synchronization construct
  • monitor 프로시저 자체는 atomic하게 구현되어 있음
  • semaphore와 다르게 lock 걸 필요가 없음
  • 모니터 내에서는 한번에 하나의 프로세스만이 활동 가능
  • 프로세스가 모니터 안에서 기다릴 수 있도록 하기 위해 condition variable 사용
    • wait
      • invoke한 프로세스는 다른 프로세스가 signal()을 invoke하기 전까지 suspend
    • signal
      • 정확하게 하나의 suspend된 프로세스를 resume
      • suspend된 프로세스가 없으면 아무일도 일어나지 않음

Process Synchronization(Concurrency Control)