1. 동기화
동시다발적으로 실행되는 프로세스들은 서로 협력하며 영향을 주고 받는다 .
이 과정에서 자원의 일관성을 보장해야한다.
→ 프로세스나 스레드는 동시에 실행되면서 공유 자원(변수, 파일, 메모리 등) 을 사용한다.
& 프로세스들의 수행 시기를 맞추는 것
: “스레드 또는 프로세스가 특정 순서대로 실행되도록 강제하는 기술”을 의미한다.
Ex )
Writer : Book.tsx 파일에 값을 저장하는 프로세스
Reader : Book.tsx 읽는 프로세스
→ Reader와 Writer 프로세스는 무작정 아무렇게나 실행되어선 안된다.
→ 실행의 순서가 있기 때문이다.
Reader 프로세스는 ‘Book.tsx 안에 값이 존재한다’는 특정 조건이 만족되어야만 실행이 가능하다.
Ex ) 문제가 생기는 경우 예시

공유자원
: 여러 프로세스 혹은 스레드가 공유하는 자원
→ 전역 변수 , 파일, 입출력장치 , 보조기억장치 등등
임계 구역
: 동시에 실행되면 문제가 발생하는 자원에 접근하는 코드 영역
→ 여러 스레드가 동시에 접근하면 문제가 발생하는 코드 영역
→ 반드시 한 번에 하나의 스레드만 실행해야 한다.
→ 앞선 예시의 ‘총합’ 변수 , ‘잔액’변수 ,등등
→ 임계 구역에 진입하고자 하면 진입한 프로세스 이외에는 대기해야 한다.

→ 임계 구역에 동시에 접근하면 자원의 일관성이 깨질 수 있다
→ 이를 레이스 컨디션이라고 한다.
: 상호 배제를 위한 동기화 도구(자물쇠 역할) , 뮤텍스 락
→ 공유 자원을 동시에 접근하는 스레드들 사이의 충돌을 막기 위해 사용되는 동기화 도구
→ 오직 하나의 스레드만 접근할 수 있도록 보장하는 기법
→ 전역 변수 하나 , 함수 두개
acquire 함수
release 함수
임계 구역에서의 작업이 끝나고 호출
현재 잠긴 임계 구역을 열기( lock을 false로 바꾸기 )
바쁜 대기
while(lock == true) /* 만약 임계 구역이 잠겨 있다면 */
; /* 임계 구역이 잠겨 있는지를 반복적으로 확인 */
Thread A Thread B
------------- ---------------
lock(mutex) ----→ lock(mutex) (대기)
임계구역 실행 (기다림)
unlock(mutex) ----→ lock 획득 → 임계구역 실행
→ 정수 변수(S)로 표현되는 동기화 기법이며, wait(P)와 signal(V) 연산으로 자원 접근을 제어한다.
→ 매번 임계구역 앞듸로 wait(),signal() 호출하기엔 사용자 입장에선 불편함.
(1) 이진 세마포어(Binary Semaphore)
(2) 카운팅 세마포어(Counting Semaphore)

전역변수 S : 임계 구역에 진입할 수 있는 프로세스의 개수를 나타내는 변수wait() : 자원 사용 요청signal() : 자원 사용 완료ex) 레스토랑에 테이블이 3개 있다면
S = 3 (테이블 3개)
손님1 → wait() → S=2 → 식사 시작
손님2 → wait() → S=1 → 식사 시작
손님3 → wait() → S=0 → 식사 시작
손님4 → wait() → S=0 → 테이블 없음 → 대기
손님1이 떠나면
signal() → S=1 → 대기 중 손님4가 식사 시작
코드 예시
class Semaphore {
constructor(max) {
this.max = max; // 동시에 실행 가능한 개수
this.current = 0; // 현재 실행 중인 작업 수
this.queue = []; // 대기 중인 resolve 함수들
}
async acquire() {
if (this.current < this.max) {
this.current++;
return Promise.resolve();
}
// 대기 상태 → resolve가 push되어, signal(=release) 때 호출됨
return new Promise(resolve => this.queue.push(resolve));
}
release() {
// 대기 중인 작업이 있다면 깨워주기
if (this.queue.length > 0) {
const resolve = this.queue.shift();
resolve();
} else {
this.current--;
}
}
}
사용
const semaphore = new Semaphore(2);
async function task(name, delay) {
await semaphore.acquire(); // wait
console.log(`${name} 시작`);
await new Promise(r => setTimeout(r, delay));
console.log(`${name} 종료`);
semaphore.release(); // signal
}
async function run() {
task("A", 2000);
task("B", 1000);
task("C", 500);
task("D", 800);
}
run();
: 상호 배제를 위한 동기화와 실행순서 제어를 위한 동기화 2개를 모두 제공한다.

정리
동기화란 여러 프로세스나 스레드가 동시에 실행되며 공유 자원(변수, 파일, 메모리 등) 을 사용할 때, 서로 간섭하지 않도록 실행 순서와 접근 방식을 조정하는 것을 의미한다. 이를 통해 데이터의 일관성을 보장하며, 실행 순서를 강제하거나(예: Reader–Writer 문제) 동시에 접근해서는 안 되는 자원에 한 번에 하나의 프로세스만 접근하도록 제한하는 상호 배제(Mutual Exclusion) 를 달성한다. 특히 임계 구역(critical section)에서 발생할 수 있는 레이스 컨디션을 방지하기 위해 운영체제는 상호 배제, 진행, 유한 대기라는 세 가지 원칙을 통해 임계구역 문제를 해결한다.
이러한 동기화를 구현하기 위해 다양한 기법이 사용되는데, 대표적으로 뮤텍스(Mutex) 와 세마포어(Semaphore) 가 있다. 뮤텍스는 단 하나의 스레드만 자원에 접근할 수 있도록 잠금(lock)을 제공하는 반면, 세마포어는 정수 값을 사용해 여러 개의 자원을 동시에 관리할 수 있어 더 일반적인 형태의 동기화 도구이다. 세마포어는 이진(Binary) 형태로 뮤텍스와 유사하게 사용되거나, 카운팅 형태로 자원이 여러 개일 때 wait/signal 연산을 통해 접근을 제어한다. 또한 모니터(Monitor) 는 상호 배제와 실행 순서 제어 기능을 모두 제공하는 고수준 동기화 도구로, 내부 큐를 통해 공유 자원 접근을 자동으로 관리하여 보다 안전하고 간편한 동기화 환경을 제공한다.
참고