[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 |