Study/CS 기초

운영체제 - 동기화와 교착상태

김 도경 2024. 10. 21. 12:37

[2024.10.21] 필수 온라인 강의 Part2 운영체제 CH04 동기화와 교착상태

  • 프로세스 뿐만 아니라 스레드도 스케쥴링, 동기화 대상이다. 모든 흐름을 가진 것은 동기화 대상
프로세스 동기화
    • 자원은 한정됨 : 운영체제는 적재적소에 효율적이고 공정하게 자원을 배분
      - 동시다발적으로 실행되는 프로세스(& 스레드) : 실행 순서와 자원의 일관성을 고려하여 보장

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

    • 실행 순서 제어를 위한 동기화
      아래 두개의 프로세스가 동시다발적으로 실행이 되었다면? 
                1. Book.txt가 없다면 파일을 만들고 값을 쓰고 저장하는 프로세스
                2. Book.txt를 읽어들이는 프로세스
      : 둘은 실행순서가 중요하다 1->2가 되어야함
    • 상호 배제를 위한 동기화
      동시에 실행되는 프로세스
                1. 2만원 입금 프로세스 : a. 잔액을 읽어들인다 b. 잔액에 2만원을 더한다 c. 더한 값을 저장한다
                2. 5만원 입금 프로세스 : a. 잔액을 읽어들인다 b. 잔액에 5만원을 더한다 c. 더한 값을 저장한다
      : 동기화를 고려하지 않으면
      (여기서는 잔액이 자원)
      : 올바른 예시: 잔액에 접근하기 전 기다려야 한다!
      (여기서는 잔액이 자원)
  • 공유 자원과 임계 구역
    - 공유 자원: 공동의 자원 (e.g. 파일, 전역 변수, 입출력장치, …)
          - 동시에 접근해서는 안 되는 자원 , 일관성을 지켜야하는 자원
          - 임계 구역(critical section) : 동시에 접근하면 문제가 발생할 수 있는 공유 자원에 접근하는 코드
          - 레이스 컨디션(race condition) : 임계 구역을 동시에 실행하여 자원의 일관성이 깨지는 현상

  • 생산자와 소비자 문제 (producer-consumer problem) : 프로세스가 동기화 되지 않았을 때 발생되는 문제
            - 동기화가 이루어지지 않았을 경우 발생할 수 있는 문제를 보여주는 고전적 문제
    - producer: 생산을 하는 프로세스(혹은 스레드) : queue에 데이터 넣기, 기존없었던 자원생산, 변수값 증가
    - consumer: 소비를 하는 프로세스(혹은 스레드) : queue에 있는 값 읽기, 없었던 자원읽어드리기, 소비, 변수값 감소
뮤텍스와 세마포어
  • 동기화를 할 수 있는 도구들, 동기화 여러 기법들 중 가장 고전적인 방법
  • 동기화 해결의 세 가지 원칙
    - 상호 배제 : 한 프로세스가 임계 구역에 진입했다면 다른 프로세스는 대기해야 함
    - 진행 : 어떤 프로세스도 임계 구역에 진입하지 않았다면 진입이 가능해야 함
    - 유한 대기 : 한 프로세스가 임계 구역 진입을 위해 대기하고 있다면 언젠간 진입이 가능해야 함

  • 뮤텍스 락 (Mutex Lock)
    - 소프트웨어적인 해결방법 : 상호 배제를 위한 동기화 도구
    - 한 마디로 자물쇠(lock)
    - 공유하고 있는 데이터가 여러 프로세스/스레드에서 접근되는 것을 막는 것을 위한 방법
    - C++에서 제공하는 뮤텍스 락 : https://en.cppreference.com/w/cpp/thread/mutex
    - 파이썬에서 제공하는 뮤텍스 락 :  https://docs.python.org/3/library/asyncio-sync.html#asyncio.Lock

    - 뮤텍스 락의 표현
          - 자물쇠 역할: 프로세스들이 공유하는 전역변수 lock
                 - True 잠김, False 안잠김
          - 자물쇠 잠그기: acquire 함수
                 - lock 이 true인지 false인지 계속 반복확인(while 루프, 잠겨있는지 열려있는지 확인),
                     : 바쁜 대기(busy waiting) : while루프를 통해 계속 확인을 하는 작업
                 - 다른 프로세스에서 lock이 false로 바꾸면(열림), lock=true실행하여 lock을 true로 바꾸고 임계구역으로 진입
                 - 임계구역에 아무나 들어가면 안 되기에 실행함
          - 자물쇠 열기: release 함수  
                 - 작업을 끝내고 나올 때 lock을 false로 바꿈

  • 세마포(semaphore) 
    - 상호 배제 & 실행 순서 제어를 위한 동기화 도구
    - C++에서 제공하는 세마포 : https://en.cppreference.com/w/cpp/thread/counting_semaphore
    - 파이썬에서 제공하는 세마포 : https://docs.python.org/3/library/asyncio-sync.html#asyncio.Semaphore
    - 카운팅 세마포와 바이너리 세마포가 있는데, 바이너리 세마포는 뮤텍스 락이랑 비슷함

    - 일반적인 상황에서도 사용 할 수 있는 동기화 도구
        - 뮤텍스 락은 기본적으로 공유 자원이 하나일 경우 상정한 동기화 도구 : lock이 하나의 경우
        - 세마포는 공유 자원이 여러 개 있을 경우도 동기화 (실행 순서 제어, 상호 배제 동기화) 가능 

    - 어원 : 철도 신호기 - 가도 된다, 안된다를 말해줌
       - 가라는 신호를 받으면 (임계 구역에) 진입해도 좋다
       - 멈추라는 신호를 받으면 (임계 구역에) 진입해서는 안된다

    - 세마포(semaphore) 의 표현
    1. 변수 S: 임계 구역에 진입할 수 있는 프로세스의 개수(사용 가능한 공유 자원의 개수)
    2. wait 함수: 임계구역에 들어가도 좋은지, 기다려야 할지를 알려주는 함수
             - while 함수로 무한루프를 함. : 무한이 진입이 가능한지 확인함
    3. signal 함수: 임계구역 앞에서 기다리는 프로세스에게 ‘이제 가도 좋다’고 신호를 주는 함수 
             - s를 1씩 증가/감소 시키는 함수임

    - 프로세스 상태 전이 활용
          - busy wait는 너무 cpu자원을 낭비함. 이를 방지하는 방법
          - 신호를 기다리는 무한 반복 대신 대기상태로 접어들게 함.

    - 실행 순서를 위한 동기화 진행방법
        - 먼저 실행할 프로세스 뒤에 signal
        - 나중에 실행할 프로세스 앞에 wait

- signal이 wait을 깨워줌

조건변수와 모니터

- 동기화를 위한 다른 방안 중 하나

 

  • 사용 이유
    - 세마포 누락
    - wait랑 signal 순서를 헷갈림
    - wait랑 signal이 중복해서 사용
  • 사용이 간편한 동기화 도구, 모니터
    - 공유 자원에 접근하기 위한 인터페이스를 각각 따로 둠
       - 정해진 인터페이스를 통해서만 들어와야함 : 다 지정되어있음
    - 인터페이스를 통해서만 접근 (상호 배제)

  • 실행 순서 제어를 위한 동기화를 위해 조건 변수(conditional variable) 사용
    - c++에서 제공하는 조건변수 : https://en.cppreference.com/w/cpp/thread/condition_variable
    - 파이썬에서 제공하는 조건 변수 :  https://docs.python.org/3/library/threading.html#condition-objects
    - 모니터의 조건변수와 별개의 조건변수
    - wait(), signal() 연산이 가능한 특별한 변수
         - 실행 순서 제어를 위한 동기화를 위해 조건 변수 사용
         - 프로세스 상태 전이가 가능한 특별한 변수
             - wait() : 호출한 프로세스를 대기 상태로 전환
             - signal() : 호출한 프로세스를 깨움
     - 조건 변수를 활용한 실행 순서 제어
         1. 아직 실행될 조건이 되지 않았을 때에는 wait을 통해 실행 중단
         2. 실행될 조건이 충족되었을 때에는 signal을 통해 실행 재개

  • 모니터를 활용하는 대표적인 프로그래밍 언어: Java
      - synchronized 키워드 : https://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
         - 내부적으로 모니터로 구성됨
교착상태(deadlock)와 해결방법
  • 프로세스는 실행을 위해 자원이 필요하다 : 서로의 자원을 무한히 기다리기만 한다면 -> 교착상태 발생
  • 식사하는 철학자 문제( N명의 철학자, 두 개의 포크로 먹을 수 있는 음식, 원형 테이블)
        - 계속 생각을 하다가, 왼쪽 포크가 사용 가능하면 집어든다. -> 계속 생각을 하다가, 오른쪽 포크가 사용 가능하면 집어든다. -> 왼쪽과 오른쪽 포크를 모두 집어들면, 정해진 시간동안 식사를 한다. ->  식사 시간이 끝나면, 오른쪽 포크를 내려놓는다. ->  오른쪽 포크를 내려놓은 뒤, 왼쪽 포크를 내려놓는다. ->  1번부터 다시 반복한다.
         - 모든 철학자들이 동시에 포크를 집어드는 순간 누구도 식사를 할 수 없음
         - 철학자 == 프로세스(혹은 스레드) / 포크 == 실행을 위해 필요한 자원 으로 생각하면 이게 교착상태이다.

  • 교착 상태 (deadlock)
    - 일어나지 않을 사건(필요한 자원의 할당)을 기다리며 무한히 대기하는 현상

    - 교착 상태 발생 조건 (***시험에 잘 나옴***)
         - 상호 배제: 동시에 자원 사용이 불가능한 경우
         - 점유와 대기: 자원을 할당받은 채 다른 자원의 할당을 기다리는 경우
         - 비선점: 강제로 자원을 빼앗을 수 없는 경우
         - 원형 대기: 자원을 원형으로 대기할 경우

  • 교착상태 해결방법
    - 교착 상태 예방
    교착 상태 발생 조건 네 가지(상호 배제, 점유와 대기, 비선점, 원형 대기)중 하나를 없애는 것 
    교착 상태가 발생 배경 원천 차단
    교착 상태가 발생하지 않음을 보장할 수 있지만, 여러 부작용이 따르는 방식
        - 상호 배제 조건 없애기
                  - 자원을 공유 가능하도록 변경
                  -  모든 자원에 대해 적용할 수 없음
        - 점유와 대기 조건 없애기
                  -  특정 프로세스에 자원을 모두 할당, 아예 할당하지 않기
                  -  자원의 활용률 저하

        - 비선점 조건 없애기
                  - 자원을 뺏을 수 있게 해버리기. : 선점스케줄
                  -  선점하여 사용 가능한 자원에 대해서는 효과적 (e.g. CPU)
                  -  모든 자원에 대해 적용 가능한 것은 아님 (e.g. 프린터기)

        - 원형 대기 조건 없애기
                  -  자원에 번호 매기기
                    : 자원에 번호를 매길 수 없음, 실행에 얼마나 사용하는지 알 수 없음, 자원의 활용이 떨어짐
                  -  오름차순으로 자원 할당


    - 교착 상태 회피
           - 교착 상태가 발생하는 이유를 자원의 무분별한 할당으로 간주
              ○ 포크가 무한한 상황에서 한 두개의 자원만을 요구했다면? (교착상태가 절대 발생하지 않음)
              ○ 포크가 두 개 있는 상황에서 여러 개의 자원을 요구했다면? (이때 교착상태가 발생됨)

           - 프로세스가 요구할 수 있는 최대자원의 양, 현재 사용중인 자원의 양, 남은 자원의 양을 고려함
           - 가장 적게 추가적인 자원이 필요한 프로세스 순으로 요구를 들어줌
           - 작업이 끝나고도 남은 자원이, 다른 프로세스의 요구량을 들어주지 않으면 교착상태가 발생할 수 있음

           - 이를 판단하는 알고리즘 == 은행원 알고리즘(banker’s algorithm)


    - 교착 상태 검출 후 회복 ( 교착 상태가 발생하면 그때 회복하는 방식)
           - 선점을 통한 회복
           - 프로세스 강제 종료를 통한 회복

    - 타조 알고리즘
           - 교착상태를 무시해버리는 알고리즘

'Study > CS 기초' 카테고리의 다른 글

운영체제 - 파일 시스템  (4) 2024.10.21
운영체제 - 가상 메모리 관리  (3) 2024.10.21
운영체제 - CPU 스케줄링  (2) 2024.10.19
운영체제 - 프로세스와 스레드  (5) 2024.10.19
운영체제 거시적으로 보기  (7) 2024.10.19