운영체제 리뷰 4 - 동기화

LeemHyungJun·2024년 6월 3일
0

Operating System

목록 보기
18/20

참고 자료 : 혼자 공부하는 컴퓨터구조 + 운영체제
사진 출처 : Operating System Concepts 10E

1. 동기화란

개요

  • 프로세스와 스레드는 동시 다발적으로 동작한다.
  • 자원의 일관성을 위해 프로세스와 스레드의 동기화 필요

<동기화의 의미>

1. 개요

  • 공동의 목적을 위해 동시에 수행되는 프로세스들은
  • 올바른 수행을 위해 동기화되어야 한다.

2. 프로세스의 동기화

  • 프로세스(스레드)들의 수행 시기를 맞추는 것
  • 실행 순서 제어
    • 프로세스를 올바른 순서대로 실행하기
  • 상호 배제
    • 동시에 접근해서는 안되는 자원에 하나의 프로세스만 접근하게 하기

<동기화 예시>

1. 실행 순서 제어를 위한 동기화

  • Reader Writer Problem
    • Writer
      • 파일에 값을 저장하는(쓰는) 프로세스
    • Reader
      • 파일에 저장된 값을 읽어들이는 프로세스
  • 실행의 순서 지켜야함!
    • reader 프로세스는 파일 안에 값이 존재한다는 특정 조건이 만족되어야 실행 가능
    • writer의 조건이 먼저 선행되어야 함

2. 상호 배제를 위한 동기화

예시 1) Bank Account Problem

  • 공유가 불가능한 자원동시 사용을 피하기 위한 동기화
  • 예시
    • 프로세스 A
      • 계좌 잔액 읽고
      • 잔액에 2만원 추가
      • 저장
    • 프로세스 B
      • 계좌 잔액 읽고
      • 잔액에 5만원 추가
      • 저장
  • 문제가 되는 상황은 (처음 잔액 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. 모니터의 구조

0개의 댓글