[운영체제] 프로세스와 스레드의 동기화 - 4/5

2023. 4. 3. 13:53기술 면접 준비

⭐ 동기화

동시다발적으로 실행되는 프로세스, 스레드는 서로 협력하며 영향을 주고받습니다. 이 과정에서 자원의 일관성을 보장해야 하는데, 이때 필요한 과정이 동기화입니다. 

* 프로세스 동기화라고 해도 스레드 또한 동기화 대상입니다.

 

목차

동기화 정의

동기화가 왜 필요할까

동기화를 하지 않을시 발생하는 문제점

동기화를 위한 도구들

 

(프로세스) 동기화 정의

동기화는 크게 두 가지를 의미합니다. 

  • 실행 순서 제어를 위한 동기화
    • 프로세스들을 올바른 순서대로 실행하기 위한 동기화
  • 상호 배제를 위한 동기화
    • 동시에 접근해서는 안 되는 자원에 하나의 프로세스만 접근하게 하는 동기화

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

발생하는 동기화 문제 : reader writer problem

 

두 프로세스가 있다고 가정하겠습니다. 하나는 Writer로 파일에 값을 저장하는 프로세스이고 하나는 Reader로 파일에 저장된 값을 읽어들이는 프로세스입니다.

 

이때 두 프로세스는 아무렇게나 실행하면 될까요? 아닙니다.

 

실행의 순서가 있기 때문인데요. 예를 들어 Reader프로세스의 경우 특정 파일 안에 값이 존재한다는 조건이 만족되어야만 실행이 가능합니다. 

 

⭐상호 배제를 위한 동기화

공유가 불가능한 자원의 동시 사용을 피하기 위한 동기화입니다.

한 번에 하나의 프로세스만 자원에 접근해야 합니다. 

 

발생하는 동기화 문제  : Bank account problem

잔액에 X원을 더하여 저장하는 프로세스 A,

잔액에 Y원을 더하여 저장하는 프로세스 B

'잔액'이 공유자원입니다.

 

이 상태에서 프로세스 A와 B를 마구잡이 실행 시 우리가 원하는 결과 잔액은 나오지 않습니다.

 

발생하는 동기화 문제: Producer & Consumer problem

물건을 계속해서 생산하는 생산자 (producer, 프로세스 혹은 스레드) - 한 번 계산 시 +1

물건을 계속해서 소비하는 소비자 (consumer, 프로세스 혹은 스레드) - 한 번 계산시 -1

'총합'이 공유자원입니다. 

 

이 상태에서 생산자를 100,000번, 소비자를 100,000번 마구잡이로 실행했을 때 총합은 0이 나와야 할 것 같지만 우리가 원하는 금액으로 나오지 않습니다.

 

우리가 생각하는 결과값이 나오지 않은 원인은 동기화가 되지 않았기 때문입니다.

 

 

여기서 의문이 하나 들 수 있습니다. 

 

동시에 접근해서는 안 되는 자원이란 어떤 건가요?

 

 

바로 알아보기 전에 짚고 넘어가야 할 개념이 있습니다. 

 

공유 자원 (shared resource)

  • 여러 프로세스 혹은 스레드가 공유하는 자원
  • 예) 전역 변수, 파일, 입출력장치, 보조기억장치....

✅ 임계 구역 (critical section)

  • 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역
  • 예) 앞선 예시의 '총합', '잔액'
  • 임계 구역에 진입하고자 하면 진입한 프로세스 이외에는 대기해야 합니다. 그렇지 않으면 문제가 발생합니다.
    • 임계 구역에 동시에 접근하면 자원의 일관성이 깨질 수 있습니다. 이를 ⭐레이스 컨디션(race condition)이라고 합니다. 
    • Bank account problem와 Producer & Consumer problem은 레이스 컨디션의 사례입니다. 

⭐상호 배제를 위한 동기화를 위한 세 가지 원칙

= 운영체제가 임계 구역 문제를 해결하는 세가지 원칙

  • 1. 상호 배제 (mutual exclusion)
    • 한 프로세스가 임계 구역에 진입했다면 다른 프로세스는 들어올 수 없다.
  • 2. 진행 (progress)
    • 임계 구역에 어떤 프로세스도 진입하지 않았다면 진입하고자 하는 프로세스는 들어갈 수 있어야 한다.
  • 3. 유한 대기 (bounded waiting)
    • 한 프로세스가 임계 구역에 진입하고 싶다면 언젠가는 임계 구역에 들어올 수 있어야 한다.

동기화 기법 중 대표적인 3가지

뮤텍스 락,

세마포,

모니터

 

뮤텍스 락

상호 배제를 위한 동기화 도구입니다. 공유 자원이 하나만 있는 경우에 적용 가능 합니다. 

예) 탈의실(공유자원, 임계 구역)에는 손님(프로세스) 한 명씩 들어갑니다. 이때 탈의실이 이용 중인지 확인하는 방법은 탈의실에 자물쇠가 걸려있다면 손님이 있다는 의미로 기다리면 됩니다. 

 

자물쇠의 기능을 코드로 구현한 게 뮤텍스 락입니다. 

 

뮤텍스 락을 구현하기 위해선 전역 변수 하나와 함수 두 개만 있으면 됩니다.

  • 자물쇠 역할을 하는 전역 변수
  • 임계 구역을 잠그는 역할을 하는 함수
    • 프로세스가 임계 구역에 진입하기 전에 호출
    • 임계 구역이 잠겨 있다면,
      • 임계 구역이 열릴 때까지 임계 구역의 상태를 반복적으로 확인(무한 대기, 무한 확인) = 바쁜 대기(busy waiting)
    • 임계 구역이 열려 있다면, 
      • 임계 구역을 잠그고 임계 구역에 진입
  • 임계 구역의 잠금을 해제하는 역할을 하는 함수
    • 임계 구역에서의 작업이 끝나고 호출
    • 현재 잠긴 임계 구역을 열기

세마포

좀 더 일반화된 방식의 동기화 도구로 공유 자원이 여러 개 있는 경우에도 적용이 가능합니다. 

세마포의 종류 중 카운팅 세마포를 지칭합니다. 

 

상호 배제를 위한 동기화, 실행 순서 제어를 위한 동기화 모두 가능합니다. 

여기서는 상호 배제를 위한 동기화 방법을 알아보겠습니다. 

 

 

세마포는 철도 신호기에서 유래한 개념입니다.

임계 구역 앞에서 멈춤 신호(STOP)를 받으면 잠시 기다리고, 임계 구역 앞에서 가도 좋다는 신호(GO)를 받으면 임계 구역에 진입합니다.

 

세마포 역시 전역 변수 한 개와 함수 두 개로 구현가능합니다.

  • 공유 자원의 개수를 나타내는 전역 변수
  • 임계 구역에 들어가도 괜찮은지, 기다려야 하는지 알려주는 함수
    • 사용할 수 있는 자원이 있는지 반복적으로 확인하는 작업 = 바쁜 대기(busy waiting)
  • 임계 구역 앞에서 기다리는 프로세스에게 GO 하라는 신호를 주는 함수

 

복잡해보이지만 아래 과정을 통해 쉽게 이해할 수 있습니다. 

 

바쁜 대기는 좋은 방법이 아닙니다,  왜 나쁠까요? 해결 방법은? 

왜냐하면 무한 대기를 하면서 무한 반복적으로 확인하는 것은 불필요한 CPU 사이클이 낭비됩니다.

 

조금 더 좋은 방법이 있습니다. 

  • 사용할 수 있는 자원이 없을 경우 해당 프로세스의 PCB를 대기 큐에 삽입하고 대기 상태로 만듦
  • 사용할 수 있는 자원이 생겼을 경우 해당 프로세스의 PCB를 대기 큐에서 꺼내 준비 큐에 삽입하고 준비 상태로 만듦

 

이를 적용하면 아래에서 확인해 볼 수 있듯 과정이 약간 달라집니다. 

 

모니터

세마포의 경우 대중적이고 훌륭한 동기화 도구이지만, 매번 임계 구역 앞뒤로 함수들을 호출해야 하는 번거로움과 실수 가능성이 있습니다. 세마포의 이와 같은 단점을 보완한 방법으로 등장한 동기화 도구가 모니터입니다.

대표적으로 모니터를 활용한 언어로는 자바가 있습니다.

 

  • 상호 배제를 위한 동기화, 실행 순서 제어를 위한 동기화 두가지 동기화 방식을 제공합니다.
  • 모니터 안에는 하나의 프로세스만 있을 수 있습니다. 
  • 모니터는 공유 자원자원에 접근하기 위한 인터페이스를 묶어 관리합니다. 프로세스는 반드시 인터페이스를 통해 공유 자원에 접근할 수 있습니다. 인터페이스에 접근하기 위한 큐를 이용해 하나의 프로세스만 들어오도록 합니다.

상호 배제를 위한 동기화

공유 자원에 접근하고자 하는 프로세스를 인터페이스를 위한 큐에 삽입한 후

큐에 삽입된 순서대로 한 번에 하나의 프로세스인터페이스를 통해 공유 자원을 이용합니다.

 

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

조건 변수(condition variable)*를 이용합니다. 

* 조건 변수 : 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수로 wait(), signal() 함수를 호출합니다.

조건 변수마다 큐가 존재합니다. 이를 통해 프로세스나 스레드의 실행 흐름을 제어할 수 있습니다.

 

조건변수.wait() 호출 시

조건 변수에 대한 에 삽입하여 대기 상태로 변경합니다. 

조건변수.signal() 호출 시

wait()으로 대기 상태로 접어든 조건 변수를 실행 상태로 변경합니다.

 

⭐ 실행 순서 제어를 위한 동기화 동작 방식

  • 특정 프로세스가 아직 실행될 조건이 되지 않았을 경우 wait를 통해 실행을 중단한다.
  • 특정 프로세스가 실행될 조건이 충족되었을 경우 signal을 통해 실행을 재개한다.

 

 

 

 

 

 


 

관련 포스팅:

1. [운영체제] 운영체제는 프로그램이다?! - 1/5

2. [운영체제] 프로세스와 스레드 - 2/5

3. [운영체제] CPU 스케줄링 알고리즘 - 3/5

4. [운영체제] 프로세스와 스레드의 동기화 - 4/5

5. [운영체제] 교착 상태(데드락, Deadlock) - 5/5

 

 

 

 

출처:

혼자 공부하는 컴퓨터구조+운영체제 도서

혼자 공부하는 컴퓨터구조+운영체제 강의