12-1 동기화란

동기화의 의미

동기화(synchronization): 작업들 사이의 수행 시기를 맞추는 것

실행의 흐름을 갖는 모든 것(프로세스, 스레드 등)은 동기화의 대상

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

생산자와 소비자 문제

생산자와 소비자가 동시에 접근해서는 안 되는 자원에 동시에 접근하면 결과값이 매번 달라지거나 이상해진다.

공유 자원과 임계 구역

공유 자원(shared resource): 동시에 실행되는 프로세스가 사용하는 공동의 자원(전역 변수, 파일, 입출력장치 등)

임계 구역(critical session): 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역

레이스 컨디션(race condition)

  • 임계 구역은 두 개 이상의 프로세스가 동시에 실행되면 안 되는 영역.
  • 잘못된 실행으로 인해 여러 프로세스가 동시 다발적으로 임계 구역의 코드를 실행하여 문제가 발생하는 경우
  • 발생의 이유: 고급 언어가 저급 언어로 변환되어 실행되는 중 발생하는 문맥 교환으로 인해
  • 해결
    • 상호 배제(mutual exclusion): 한 프로세스가 임계 구역에 진입하면 다른 프로세스는 임계 구역에 들어올 수 없음
    • 진행(progress): 임계 구역에 어떤 프로세스도 진입하지 않았다면 임계 구역에 진입하고자 하는 프로세스는 들어갈 수 있어야 한다.
    • 유한 대기(bounded wating): 한 프로세스가 임계 구역에 들어오기 위해 무한정 대기해서는 안 된다(언젠가는 들어올 수 있어야 한다).

12-2 동기화 기법

동기화 도구: 뮤텍스 락, 세마포어, 모니터, …

뮤텍스 락

  • 뮤텍스 락(MuTex lock: MUTual EXclusion lock)
  • 동시에 접근해서는 안되는 자원에 동시에 접근하지 않도록 만드는 도구
  • 하나의 공유 자원에 접근하는 프로세스를 관리
  • 구성
    • lock: 프로세스들이 공유하는 전역 변수 lock
    • acquire
      • 임계 구역에 진입하는 프로세스가 임계구역에 진입하기 전에 실행하는 잠그는 함수
      • 임계 구역이 잠겨있다면 열릴 때까지 반복적으로 확인
      • 임계 구역이 열려있다면 임계 구역을 잠금
    • release
      • 실행하는 잠금을 해제하는 함수
      • 임계 구역에서의 작업이 끝나고 호출
  • Busy wait: 임계 구역의 잠금 여부를 쉴 새 없이 반복하며 확인

세마포어

  • 세마포어(semaphore)
    • 이진 세마포어(binary semaphore): 뮤텍스 락과 비슷한 개념
    • 카운팅 세마포어(counting semaphore)
  • 공유 자원이 여러 개 있는 상황에서도 적용이 가능한 동기화 도구
  • 구성
    • 전역 변수 S: 임계 구역에 진입할 수 있는 프로세스의 개수(사용 가능한 공유 자원의 개수)
    • wait: 임계 구역에 들어가도 좋은지, 기다려야 할지를 알려주는 함수
    • signal: 기다리는 프로세스에 가도 된다는 신호를 주는 함수
  • busy wait으로 wait을 반복적으로 호출

busy wait 방지

  • busy wait으로 인한 CPU 낭비를 막기 위함
  • wait 함수는 사용할 수 없는 자원이 없다면 그 프로세스의 PCB를 세마포어를 위한 대기 큐에 집어넣는다.
    • OS(운영체제)는 자원을 사용할 수 있다면 자원을 할당한 채로 준비큐로 보낸다(바로 실행 X)
    • 따라서 준비큐의 앞에 그 자원을 사용하는 다른 프로세스는 실행될 때 자원이 없으므로 세마포어를 위한 대기큐로 가게 된다.
    • 준비큐에서 애초에 자원 할당을 고려하지 못함: 실행 전에는 코드를 몰라 어디가 임계구역인지 알 수 없다.

동시 실행 프로세스의 실행 순서 제어

  • 먼저 실행할 프로세스 뒤에 signal 함수, 다음에 실행할 프로세스 앞에 wait 함수 붙임
    • 다음에 실행할 프로세스가 먼저 실행되도 wait함수로 인해 기다림
    • 실제로는 나중에 실행된 ‘먼저 실행할 프로세스’가 실행된 뒤 signal이 호출됨
    • 애초에 코드를 짤때 논리적 실행순서를 고려하여 넣어놓음

모니터

  • 모니터(monitor)
  • 공유자원 활용에 대한 일종의 소프트웨어 덩어리임
    • 프로그래밍 언어 차원에서 지원하는 기능
    • 개발자가 함수를 “모니터 안에서 실행되는 것임”이라고 정의해주면 운영체제와 컴파일러가 상호 배제 문제를 관리해줌
    • 세마포어 처럼 개발자가 고려할 필요가 없음
  • 모니터 안에는 하나의 프로세스만 존재할 수 있음
    • 모니터 내에 정의된 메서드를 실행하는 프로세스는 하나뿐이어야 한다는 의미
    • 공유자원은 여러 개 존재할 수도 있다.
    • 따라서 하나의 공유자원에 대한 메서드를 사용하느라 다른 공유자원은 비어있을 수도 있다.
    • 이것은 동시성의 성능에 영향을 끼칠 수 있음
    • Lock Granularity: 어떤 자원들을 같은 모니터로 묶을 것인가?
      • Coarse-graind locking: 여러 자원을 묶어 구현은 쉽지만 동시성 성능이 떨어짐
      • FIne-grained locking: 자원별로 모니터를 쪼개 성능을 최대화
  • 세마포어에서 매번 임계 구역 앞뒤로 일일이 waitsignal을 명시하긴 번거롭다.
    • 혹은 잘못 명시할 가능성도 있다.
  • 따라서 공유 자원에 접근하기 위한 인터페이스(통로)를 묶어 관리
    • 인터페이스를 통해서만 공유 자원에 접근 가능하도록 제어
    • 상호 배제를 위한 큐가 존재하고 여기서 필요한 만큼씩 모니터에 진입
    • busy wait 방지를 위한 세마포어 대기큐와 비슷한 개념
  • 조건 변수(condition variable)
    • 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수
      • 특정 프로세스가 아직 실행될 조건이 되지 않았을 때에는 wait을 통해 실행을 중단한다.
      • 특정 프로세스가 실행될 조건이 충족되었을 때에는 signal을 통해 실행을 재개한다.
    • 조건 변수를 위한 큐(모니터의 큐와 다름)
    • 어떤 프로세스가 조건 변수 x에 대해 x.wait()을 호출하면 그 프로세스는 조건 변수를 위한 큐로 들어감
      • 호출하는 이유: 애초에 코드에 있기 떄문
        • 어떤 프로세스에 if not 데이터, x.wait()이라고 코드를 짬
        • 이게 없다면 자원은 없어 프로세스 실행이 완료되지 못하지만 모니터에서 프로세스가 안나감
        • 데이터를 생성하고 저장하는 프로세스가 실행되지 않아 데드락에 빠지게 됨
          • 데이터 생성 및 저장 프로세스에는 signal을 실행해 놓으면 됨
    • 다른 프로세스가 x.signal()을 호출하면 다시 모니터 안으로 돌아와 실행이 재개된다.
    • 한 모니터에는 한 프로세스만 존재하므로 아래 조건 중 하나로 실행된다.
      • signal호출 프로세스가 떠난 뒤
      • signal호출 프로세스의 실행을 일시 중단하고 자신이 실행된 뒤 다시 signal호출 프로세스의 실행을 재개

세마포어와 모니터

  • 세마포어에서는 waitsignal을 상호 배제로서도 사용하고, 순서 제어로서도 사용함
  • 모니터에서는 상호 배제는 모니터가 해주므로 waitsignal을 오롯이 논리적인 조건(순서)를 위해서 사용해야 함