프로세스는 운영체제(OS)에서 실행 중인 프로그램을 의미하고, 스레드는 프로세스 내에서 실행되는 작은 작업 단위이다.
프로세스는 각각 독립적인 메모리 공간을 가지는 반면, 스레드는 같은 프로세스 내에서 메모리를 공유하여 빠르게 실행한다.
1. PCB
컨텍스트 스위칭
운영체제(OS)가 현재 실행 중인 프로세스(또는 스레드)의 상태(Context)를 저장하고, 새로운 프로세스를 실행하기 위해 기존 상태를 복원하는 과정이다. 이때 PCB에 저장하고 불러온다.
멀티태스킹 환경에서 CPU가 여러 프로세스를 빠르게 전환하기 위해 필요하다.
- 캐시 미스
컨텍스트 스위칭이 발생하면 CPU 캐시에 저장된 기존 프로세스의 데이터가 새로운 프로세스의 데이터로 교체된다. 기존 캐시 데이터가 무효화되므로 새로운 프로세스의 데이터를 캐시에 로드하는 과정에서 초기에 캐시 미스(Cache Miss)가 증가한다. - 컨텍스트 스위칭 시 캐시 미스로 인한 성능 저하
컨텍스트 스위칭은 기존 프로세스의 상태를 저장하고 새로운 프로세스를 로드하는 과정이므로 추가적인 CPU 오버헤드가 발생한다. 또한, 캐시 미스로 인해 RAM에서 데이터를 로드해야 하므로 추가적인 성능 저하가 발생할 수 있다.
→ 즉, 컨텍스트 스위칭이 많아질수록 CPU가 불필요한 메모리 접근을 많이 하게 되어 성능이 떨어진다.
2. 멀티프로세싱
IPC
운영체제(OS)가 같은 시스템 내에서 실행 중인 여러 프로세스가 데이터를 주고받을 수 있도록 제공하는 메커니즘이다. 프로세스는 기본적으로 독립적인 메모리 공간을 가지므로, 서로 직접 데이터를 공유할 수 없기 때문에 IPC가 필요하다.
- 공유 메모리
- 여러 프로세스가 동일한 메모리 공간을 공유하여 데이터를 교환하는 방식이다.
- 가장 빠른 IPC 방식이며, 쓰기 및 읽기 빈도가 높아질 경우 메시지 동기화가 필요하다.
- 소켓
- 같은 컴퓨터 또는 네트워크를 통해 프로세스 간 통신을 지원하는 방식이다.
- 로컬 프로세스 간 또는 네트워크를 통한 원격 프로세스 간 통신이 가능하다.
- 파이프
- 한 프로세스의 출력을 다른 프로세스의 입력으로 전달하는 방식이다.
- 단방향(One-Way) 통신만 가능하며, 부모-자식 프로세스 간 사용 가능하다.
- 네임드 파이프
- 파일 시스템을 통해 데이터를 교환하는 방식이다.
- 이름을 가진 파이프를 사용하여 독립된 프로세스 간 통신이 가능하며, 양방향(Bidirectional) 통신이 가능하다.
3. 멀티스레딩
하나의 프로세스 내에서 여러 개의 스레드(Thread)를 생성하여 동시에 실행하는 기술로, CPU 활용도를 높이고, 프로그램 실행 속도를 향상시킬 수 있다.
스레드들은 같은 메모리 공간(Code, Data, Heap)을 공유하며, 개별적인 Stack을 가진다.
→ 즉, “멀티스레딩은 하나의 프로그램(프로세스)에서 여러 작업을 동시에 실행하는 기술이다.
Stack이 개별적으로 할당되는 이유
Stack은 함수 호출(Call), 지역 변수(Local Variables), 리턴 주소(Return Address)를 저장하는 공간이다.
멀티스레딩(Multithreading)에서 각 스레드는 자신만의 Stack을 개별적으로 할당받는데, 각 스레드는 독립적으로 함수 호출을 수행하고, 지역 변수를 관리해야 하기 때문이다.
4. 공유 자원과 임계 영역
공유 자원
공유 자원이란 시스템 안에서 각 프로세스, 스레드가 동시에 접근할 수 있는 자원을 의미한다.
대표적인 공유 자원
- 전역 변수(Global Variables) → 여러 스레드가 접근 가능
- 파일(File) → 여러 프로세스가 읽고 쓸 수 있음
- 데이터베이스(Database) → 여러 요청이 동시에 접근할 수 있음
- 메모리(Shared Memory) → 여러 프로세스가 공유하는 메모리 영역
멀티스레딩(Multithreading) 또는 멀티프로세싱(Multiprocessing) 환경에서는 여러 스레드/프로세스가 동일한 자원(메모리, 파일 등)을 공유할 수 있다. 이때, 여러 스레드/프로세스가 동시에 접근할 경우 데이터 충돌이 발생할 수 있다.
공유 자원을 두 개 이상의 프로세스가 동시에 읽거나 쓰는 상황을 경쟁 상태라고 한다.
임계 영역(Critical Section)
임계 영역이란 여러 프로세스/스레드가 동시에 접근하면 충돌이 발생할 수 있는 공유 자원(Shared Resource)에 대한 코드 블록을 말한다. 즉, 여러 프로세스가 자원을 동시에 참조하여 값(공유하는 변수명, 파일 등)이 오염될 위험 가능성이 있는 영역이다.
임계 영역은 보호하지 않으면 데이터 충돌(Race Condition)이 발생할 수 있으므로, 하나의 스레드만 임계 영역을 실행하도록 보호해야 한다. 이때 뮤텍스, 세마포어, 모니터 등의 방법을 사용하며, 이는 모두 상호 배제(Mutual Exclusion), 한정 대기(Bounded Waiting), 진행(progress)이라는 조건을 만족한다.
- 뮤텍스(Mutex)
하나의 프로세스/스레드만 임계 영역에 접근할 수 있도록 잠금(Lock)을 사용하여 상호배제를 달성하는 기법이다. 한 스레드가 Lock을 획득하면 다른 스레드는 대기해야 하며, Lock을 해제해야 다른 스레드가 접근 가능하다.
- 세마포어(semaphore)
사용하고 있는 프로세스/스레드의 수를 공통으로 관리하는 하나의 값을 이용해 상호배제를 달성하는 기법이다.
- 각 프로세스는 세마포어의 값을 확인하고 변경할 수 있다.
- 자원을 사용하지 않는 상태가 될 때, 대기하던 프로세스가 즉시 자원을 사용한다.
- 이미 다른 프로세스에 의해 사용중이라는 사실을 알게 되면, 재시도 전에 일정시간 대기해야 한다.
- wait과 signal을 통해 구현된다.
세마포어는 바이너리 세마포어(Binary Semaphore)와 카운팅 세마포어(Counting Semaphore) 두 가지로 나뉜다.
바이너리 세마포어(Binary Semaphore)
- “0 또는 1”의 값을 가지며, 한 번에 하나의 스레드만 공유 자원에 접근 가능하다. (뮤텍스와 유사)
- 값이 1이면 리소스를 사용할 수 있고, 0이면 다른 스레드는 대기해야 한다.
- 뮤텍스와 다르게 소유권이 없으며, 다른 스레드가 세마포어를 해제(Release)할 수도 있다.
바이너리 세마포어의 동작 원리
카운팅 세마포어(Counting Semaphore)
- “0 이상의 값”을 가지며, 여러 개의 스레드가 동시에 접근 가능하다.
- 세마포어 값이 0이 되면 추가 스레드는 대기해야 한다.
- 파일 서버, 데이터베이스 연결 제한, 네트워크 트래픽 제어 등에 사용된다.
카운팅 세마포어의 동작 원리
뮤텍스와 세마포어의 차이점
1. 동기화 대상의 개수
- Mutex는 동기화 대상이 only 1개일 때 사용
- Semaphore는 동기화 대상이 1개 이상일 때 사용
2. Mutex는 자원 소유 가능 + 책임을 가지는 반면, Semaphore는 자원 소유 불가
3. Mutex는 소유하고 있는 스레드만이 Mutex를 해제할 수 있다.
- 모니터(Monitor)
- 모니터는 자원에 대한 접근을 객체화하여 한 번에 하나의 스레드만 자원에 접근할 수 있도록 한다.
- 모니터 큐를 통해 공유 자원에 대한 작업들을 순차적으로 처리한다.
- 세마포어는 프로그래머가 signal과 wait 함수를 사용해서 동기화를 구현해야 하는 반면, 모니터는 내부에서 동기화를 관리해주기 때문에 사용방법이 간단하다.
- 프로그래밍 언어 수준에서 제공되기도 한다. (Java - synchronized, Python - threading.Condition)
5. 교착 상태(DeadLock)
두 개 이상의 프로세스들이 서로가 가진 자원을 기다리면서 영원히 대기하는 상태를 말한다.
교착 상태 발생 조건
- 상호배제
: 한 프로세스가 사용하는 자원을 다른 프로세스가 사용할 수 없는 상태이다. - 점유 대기
: 자원을 할당받은 상태에서 다른 자원을 할당 받기를 기다리는 상태이다. → 프로세스는 자신의 실행 전체 과정에서 필요한 자원을 필요할 때마다 조금씩 확보하고 실행해나간다. 그러다 어느 시점에 할당이 불가능한 자원 때문에 이미 확보한 자원들을 소유한 채 대기 상태가 되어버려 교착 상태에 빠질 가능성이 커질 수 있다. - 비선점
: 어떤 프로세스도 다른 프로세스의 자원을 강제로 빼앗지 못하는 상태이다. - 환형 대기
: 프로세스들이 원의 형태로 자원을 대기하는 상태이다. → 프로세스들이 자신의 자원은 보유한 채로 서로 상대방의 자원을 요청할 때 환형 대기가 발생한다.
→ 위 4가지를 동시에 만족하면 교착 상태가 발생할 수 있다.
교착 상태 해결 방법
1. 교착상태 예방 (Deadlock Prevention)
교착상태 발생 조건 4가지(상호 배제, 점유 및 대기, 비선점, 순환 대기) 중 하나 이상을 제거하여 교착상태를 원천적으로 차단하는 방법이다. 하지만 이는 시스템의 처리량이나 효율성을 떨어트릴 수 있다.
2. 교착상태 회피(Avoidance)
교착상태가 발생할 가능성이 있는 상황을 피하도록 운영체제가 자원 할당을 조절하는 방법이다. 자원의 현재 상태를 분석하여, 교착상태가 발생할 위험이 있으면 자원 할당을 거부한다.
시스템의 프로세스들이 요청하는 모든 자원을, 데드락을 발생시키지 않으면서도 차례로 모두에게 할당해 줄 수 있다면 안정 상태(safe state)에 있다고 말한다. 반면, 불안정 상태는 안정 상태가 아닌 상황을 말합니다. 즉, 데드락 발생 가능성이 있는 상황이며, 교착 상태(데드락)는 불안정 상태일 때 발생할 수 있다.
은행원 알고리즘(Banker’s Algorithm)
다익스트라가 제안한 기법으로, 어떤 자원의 할당을 허용하는지에 관한 여부를 결정하기 전에, 미리 결정된 모든 자원들의 최대 가능한 할당량을 가지고 시뮬레이션해서 Safe state에 들 수 있는지 여부를 검사한다. 즉 대기중인 다른 프로세스들의 활동에 대한 교착 상태 가능성을 미리 조사하는 것이다.
3. 교착상태 탐지 및 복구 (Deadlock Detection & Recovery)
운영체제가 주기적으로 교착상태를 검사하고, 발생하면 해결하는 방법이다.
- 탐지 방법
- Allocation, Request, Available 등으로 시스템에 데드락이 발생했는지 여부를 탐색한다.
- 자원 할당 그래프(Resource Allocation Graph, RAG)를 사용하여 교착상태 발생 여부를 확인한다.
- 복구 방법
- 프로세스 종료(Process Termination) : 교착상태에 있는 프로세스를 강제 종료하여 자원을 해제한다.
- 자원 선점(Resource Preemption) : 특정 프로세스에서 자원을 강제로 회수하여 다른 프로세스에게 할당한다.
'CS' 카테고리의 다른 글
[OS] Blocking vs Non-Blocking, Sync vs Async (0) | 2025.02.18 |
---|---|
[DB] NoSQL (1) | 2024.04.06 |
[Network] 프록시(Proxy) (0) | 2024.04.06 |
[자료구조] 힙(Heap) (0) | 2024.03.07 |
[SE] OOP란? (1) | 2024.03.04 |