
프로세스 동기화
동시다발적으로 실행되는 프로세스들은 서로 협력하며 영향을 주고 받는다
그러므로 프로세스들의 동기화를 고려해야 한다
동기화란?
- 프로세스들의 수행 시기를 맞추는 것
- 실행 순서 제어 : 프로세스를 올바른 순서대로 실행하기
- 상호 배제 : 동시에 접근해서는 안되는 자원에 하나의 프로세스만 접근하게 하기
- 공동의 목적을 위해 동시다발적으로 수행되는 프로세서들은 자원의 일관성을 유지하며 실행되어야 함
그래서 동기화가 필요함- ex) 워드프로세서 : 맞춤법 검사, 읽기, 출력 등 다양한 프로세스들이 동시에 실행
각각 움직이면 안됨
- ex) 워드프로세서 : 맞춤법 검사, 읽기, 출력 등 다양한 프로세스들이 동시에 실행
- 실행의 문맥을 갖는 모든 대상은 동기화 대상이기에 스레도드 동기화 대상임
동기화를 하지않으면 발생하는 대표적인 문제
실행 순서 제어를 위한 동기화 : reader writer problem
- Writer : Book.txt 파일에 값을 저장하는 프로세스
- Reader : Book.txt 파일에 저장된 값을 읽어드리는 프로세스

- Reader 프로세스는 'Book.txt' 안에 값이 존재한다는 특정 조건이 만족되어야만 실행 가능
- 따라서 아무렇게나 실행되어선 안되고 실행의 순서를 지켜야 함(Writer -> Reader)
- 이렇듯, 동시다발적으로 실행되는 두 개 이상의 프로세스가 있을 때 실행 순서를 제어하도록 동기화 해주는 것이 실행 순서 제어를 위한 동기화임
상호 배제를 위한 동기화 : Bank account problem
- 공유 불가능한 자원의 동시 사용을 피하기 위한 동기화
- 한 번에 하나의 프로세스만 접근해야 하는 자원에 동시 접근을 피하기 위한 동기화
- 예시

- 현재 계좌 잔액 10만원
- 프로세스 A : 현재 잔액에 2만원을 추가하는 프로세스
- 프로세스 B : 현재 잔액에 5만원을 추가하는 프로세스
- 동기화 없이 실행했을 때 실제 실행 결과

- 동기화를 적용한 실행 결과

Producer & Consumer problem
- 물건을 계속해서 생산하는 생산자(producer, 프로세스 혹은 스레드)
- 물건을 계속해서 소비하는 소비자(consumer, 프로세스 혹은 스레드)
- '총합' 변수를 공유하는 상황에서 발생하는 생산자-소비자 문제
- 예시

- 이 상태에서 생산자를 10만번, 소비자를 10만번 실행하면 총합 값은
0과 다른 값이 되거나 오류가 발생해버림
=> 동기화가 되지 않아 발생한 문제. 즉, 동시에 접근해서는 안 되는 자원에 동시에 접근했기 때문

공유 자원과 임계 구역
- 그렇다면 동시에 접근해서는 안되는 자원이 뭘까?
- 공유 자원(Shared Resource) & 임계 구역(Critical Section)
- 공유 자원 : 여러 프로세스 혹은 스레드가 공유하는 자원을 의미
- 전역 변수, 파일, 입출력장치, 보조기억장치 등등..
- 생산자, 소비자 이 두 개의 프로세스가 "총합"이라고 하는 변수를 공유 => 공유 자원이라고 할 수 있음
- 임계 구역 : 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역
- 앞선 예시의 '총합' 변수, '잔액' 변수 등에 접근하는 코드(읽기, 더하기 등등)
- 공유 자원에 접근하는 코드 중 동시에 실행하면 문제가 발생하는 코드 영역

- 임계 구역에 진입하고자 하면 진입한 프로세스 이외에는 대기해야 함
- 레이스 컨디션(race condition) : 임계 구역에 동시에 접근하여 자원의 일관성이 깨진 상태
- 앞의 3개의 사례(읽기 쓰기, 은행 계좌, 생산자 소비자 문제) 모두 레이스 컨디션이라고 할 수 있음
- C, Python과 같은 고급 언어는 컴퓨터 내부에서 실행될 때 저급 언어로 변환됨

- 그래서 1줄의 소스코드여도 내부에서 변환을 하면 한 줄이 아님
- 그래서 내부에서 실행 중 문맥교환이 일어나면 총합을 1씩 증감하는 간단한 코드도 예상치못한 결과가 발생할 수 있음
- 그러므로 운영체제는 임계구역에서 자원의 일관성이 깨지지 않도록(레이스 컨디션이 발생하지 않도록) 관리 해야함

상호 배제를 위한 동기화를 위한 3가지 원칙
1. 상호 배제 (mutual exclusion)
- 한 프로세스가 임계 구역에 진입했다면 다른 프로세스는 들어올 수 없음
2. 진행(progress)
- 임계 구역에 어떤 프로세스도 진입하지 않았다면 진입하고자 하는 프로세스는 들어갈 수 있어야 함
3. 유한 대기(bounded wating)
- 한 프로세스가 임계 구역에 진입하고 싶다면 언젠가는 임계 구역에 들어올 수 있어야 함
- 임계 구역에 들어오기 위해 무한정 대기해서는 안됨
동기화 기법
- 여러가지가 있지만 대표적인 3가지
- 뮤텍스 락, 세마포, 모니터
뮤텍스 락
- 상호 배제를 위한 동기화 도구
- 탈의실에 있는 자물쇠 같은 역할
- 손님은 프로세스, 탈의실 내부는 임계구역
- 자물쇠를 통해 진행중인 프로세스가 있는지 확인하고 실행

뮤텍스 락 형태
- 전역 변수 하나, 함수 두개
- 자물쇠 역할 : 프로세스들이 공유하는 전역 변수 lock(boolean)
- 임계 구역을 잠그는 역할 : acquire 함수
- 프로세스가 임계 구역에 진입하기 전에 호출
- 임계 구역이 잠겨 있다면
임계 구역이 열릴 때까지 (lock이 false가 될 때까지) 임계 구역을 반복적으로 확인 - 임계 구역이 열려있다면
임계 구역을 잠그기(lock을 true로 바꾸기)
- 임계 구역의 잠금을 해제하는 역할 : release 함수
- 임계 구역에서의 작업이 끝나고 호출
- 현재 잠긴 임계 구역을 열기(lock을 false로 바꾸기)
- 임계 구역 접근이 필요하면 acquire 함수 호출 → 임계 구역이 잠겨있다면 열릴 때까지 반복 확인 → 열리면 lock을 true로 자물쇠를 잠근 뒤 코드에 접근 → 볼일 다 보면 release 함수 호출 → 잠긴 임계구역 열기(lock = false)
코드 구현
- 간단히 구현한 것으로 실제로는 더 길고 복잡함
- 프로그래밍 언어에서도 지원해주는 경우도 있음


위에서 봤던 생산자-소비자 문제를 봤을 때 아래 코드와 같음
acquire();
// '총합' 변수 접근
release();
바쁜 대기(busy waiting)

- 무한히 대기하면서 반복적으로 임계구역이 열려있는지 아닌지를 확인해 보는 것
- 탈의실이 비었나 문을 계속 덜컹거리며 열어보려 하는 것과 같음
- CPU 사이클 낭비!
참고) 스핀락(spinlock) - 강의 QnA
- 뮤텍스락과 비슷(while문 내부를 반복하며 lock을 확인)
- 뮤텍스락은 뒤에 나올 세미포(semaphore)처럼 대기상태 + 큐를 사용하지만 스핀락은 사용 안함
- 보통 스핀락은 스핀락이라고 명시되어 있음
- 구체적인 구현은 구현체에 따라 다를 수 있음
세마포(semaphore)
- 좀 더 일반화된 방식의 동기화 도구
- 공유 자원이 여러 개 있는 경우에도 적용 가능
- 상호 배제를 위한 동기화뿐만 아니라 실행 순서를 위한 동기화도 제공
(실행 순서를 위한 동기화는 아래에서 알아볼 예정) - 세마포의 종류로는 이진 세마포와 카운팅 세마포가 있음
- 이진 세마포는 뮤테스락과 비슷하기 때문에 뒤에서 설명하는 건 카운팅 세마포임

- 세마포라는 단어는 철도 신호를 의미함
- 임계 구역 앞에서 멈춤 신호를 받으면 잠시 기다리기
- 임계 구역 앞에서 가도 좋다는 신호를 받으면 임계 구역 진입

세마포의 형태
- 전역 변수 하나, 함수 두개
- 전역 변수 S : 임계 구역에 진입할 수 있는 프로세스의 개수(사용 가능한 공유 자원의 개수)
- wait 함수 : 임계 구역에 들어가도 좋은지, 기다려야 할지를 알려주는 함수
- signal 함수 : 임계 구역 앞에서 기다리는 프로세스에 '이제 가도 좋다'고 신호를 주는 함수
- 전공서마다 함수 명은 다름
- 임계구역 앞뒤로 wait과 signal 함수 호출
wait()
// 임계 구역
signal()
코드 구현


예시
- 세 개의 프로세스 P1, P2, P3가 두 개의 공유 자원(S=2)에 P1,P2,P3 순서로 접근한다고 가정

바쁜 대기

- 세마포 역시 바쁜 대기가 발생할 수 있음
바쁜 대기 해결 방법
- 사용할 수 있는 자원이 없을 경우 대기 상태로 만듦
(해당 프로세스의 PCB를 대기 큐에 삽입) - 사용할 수 있는 자원이 생겼을 경우 대기 큐의 프로세스를 준비 상태로 만듦
(해당 프로세스의 PCB를 대기 큐에서 꺼내 준비 큐에 삽입)
코드 구현(sudo code)

예시
- 세 개의 프로세스 P1, P2, P3가 두 개의 공유 자원(S=2)에 P1,P2,P3 순서로 접근한다고 가정

세마포의 실행 순서 동기화
- 실행 순서 동기화를 하기 때문에 순서를 보장할 수 있음
- 방법
- 세마포의 변수 S를 0으로 두고
- 먼저 실행할 프로세스 뒤에 signal 함수
- 다음에 실행할 프로세스 앞에 wait 함
- P1이 먼저 실행되면 실행 순서 ok
- P2가 먼저 실행되더라도 wait에 걸리고 S가 -1이 되어 대기 큐에 삽입되므로 P1이 먼저 실행됨

모니터
- 세마포는 매번 임계구역 앞뒤로 함수를 호출해야하기 때문에 번거로움과 실수의 위험이 큼
- 그래서 사용자(개발자)가 다루기에 편한 동기화 도구인 "모니터" 가 생김
- 모니터를 활용하는 대표적인 프로그래밍 언어로는 JAVA가 있음
- 모니터는 상호 배제를 위한 동기화와 실행 순서 제어를 위한 동기화 두 가지를 모두 제공

모니터의 상호 배제를 위한 동기화
- 공유 자원과 공유 자원에 접근하기 위한 통로를 묶어서 관리
- 인터페이스를 위한 큐
- 공유 자원에 접근하고자 하는 프로세스를 (인터페이스를 위한) 큐에 삽입
- 큐에 삽입된 순서대로 (한 번에 하나의 프로세스만) 공유 자원 이용
- 공유 자원에 접근하고자 하는 프로세스와 스레드는 반드시 특정 인터페이스를 통해 접근해야 함

실행 순서 제어를 위한 동기화
- 특정 프로세스가 아직 실행될 조건이 되지 않았을 때에는 wait을 통해 실행을 중다
- 특정 프로세스가 실행될 조건이 충족되었을 때에는 signal을 통해 실행을 재개
- 조건 변수(condition variable) 이용
- 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수
- wait이나 signal이라고 함수를 호출할 수 있는 특별한 변수
- 조건변수.wait() : 대기 상태로 변경, 조건 변수에 대한 큐에 삽입
- 조건변수.signal() : wait으로 대기 상태로 접어든 조건 변수를 실행 상태로 변경
- 각각의 조건 변수에 대한 큐로 실행 순서를 제어함
- 조건 변수에 대한 큐는 앞에서 말한 상호 배제를 위한 큐와 다름

- 프로세스 내에서 조건 변수 x에 대해 wait 함수 호출
→ 조건 변수 x에 대한 큐에 프로세스 삽입(대기 상태로 변경)

- 모니터 안에는 하나의 프로세스만 있을 수 있음
- siganl호출 방식에는 아래 두 가지가 있음
- wait()을 호출했던 프로세스는 signal()을 호출한 프로세스가 모니터를 떠난 뒤에 수행을 재개
- signal()을 호출한 프로세스의 실행을 일시 중단하고 자신이 실행된 뒤 다시 signal()을 호출한 프로세스의 수행을 재개
- 선점/비선점과 비슷하지만 별개의 개념임. wait을 해도 문맥 교환이 일어날 수 있음

출처 : 혼자 공부하는 컴퓨터구조 + 운영체제 (저자 강민철)
'취업역량강화 > 컴퓨터공학' 카테고리의 다른 글
| [운영체제] 가상 메모리 (연속 메모리 할당, 페이징을 통한 가상 메모리 관리) (0) | 2026.02.23 |
|---|---|
| [운영체제] 교착 상태와 해결 방법 (0) | 2026.02.21 |
| [운영체제] CPU 스케줄링과 스케줄링 알고리즘 (0) | 2026.02.17 |
| [운영체제] 파이썬으로 프로세스와 스레드 다루기 (0) | 2026.02.15 |
| [운영체제] 프로세스와 스레드 (0) | 2026.02.13 |