프로세스(process) : 컴퓨터에서 실행되고 있는 프로그램. CPU 스케줄링의 대상이 되는 작업(task)
과 거의 같은 의미로 쓰인다.
스레드(thread) :프로세스 내 작업의 흐름
프로그램이 메모리에 올라가면 프로세스가 되는 인스턴스화
가 일어나고, 이후 운영체제의 CPU 스케줄러
에 따라 CPU가 프로세스를 실행한다.
3.3.1 프로세스와 컴파일 과정
프로세스 : 프로그램이 메모리에 올라가 인스턴스화된 것
컴파일러가 컴파일 과정을 통해 컴퓨터가 이해할 수 있는 기계어로 번역하여 실행할 수 있는 파일을 만든다.
컴파일 과정
- 전처리 : 소스 코드의 주석을 제거하고 #include 등 헤더 파일을 병합해 매크로를 치환
- 컴파일러 : 오류 처기, 코드 최적화 작업을 하며 어셈블리어로 변환
- 어셈블러 : 어셈블리어는 목적 코드(object code)로 변환됨.
- 링커 : 프로그램 내에 있는 라이브러리 함수 또는 다른 파일들과 목적 코드를 결합해 실행 파일을 만듦. 실행 파일의 확장자는 .exe 또는 .out
- 라이브러리 :
정적 라이브러리
와 동적 라이브러리
로 나뉨.
정적 라이브러리와 동적 라이브러리
- 정적 라이브러리 : 프로그램 빌드 시 라이브러리가 제공하는 모든 코드를 실행 파일에 넣는 방식으로 라이브러리를 쓰는 방법.
- 장점 : 시스템 환경 등 외부 의존도가 낮음
- 단점 : 코드 중복 등 메모리 효율성이 떨어짐
- 동적 라이브러리 : 프로그램 실행 시 필요할 때만 DLL이라는 함수 정보를 통해 참조하여 라이브러리를 쓰는 방법.
- 장점 : 메모리 효율성 좋음
- 단점 : 외부 의존도 높아짐
3.3.2 프로세스의 상태
생성(create)
- 프로세스가 생성된 상태.
fork()
또는 exec()
함수를 통해 생성한다.
- 이때
PCB
가 할당된다.
fork()
부모 프로세스의 주소 공간을 그대로 복사하며, 새로운 자식 프로세스를 생성하는 함수. 주소 공간만 복사하며 부모 프로세스의 비동기 작업 등을 상속하진 않는다.
exec()
새롭게 프로세스를 생성하는 함수.
대기 상태(ready)
- 메모리 공간이 충분하면 메로기를 할당받고 아니면 아닌 상태로 대기함.
- CPU 스케줄러로부터 CPU 소유권이 넘어오기를 기다리는 상태.
대기 중단 상태(ready suspended)
실행 상태(running)
- CPU 소유권과 메모리를 할당받고 인스트럭션을 수행 중인 상태. 이를
CPU burst
가 일어났다고도 표현한다.
중단 상태(blocked)
- 어떤 이벤트가 발생한 이후 기다리며 프로세스가 차단된 상태.
I/O 디바이스
에 의한 인터럽트로 이런 현상이 많이 발생한다.
- ex) 프린트 인쇄 버튼을 눌렀을 때 프로세스가 잠깐 멈춘 듯한 때
일시 중단 상태(blocked suspended)
대기 중단
과 유사.
- 중단된 상태에서 프로세스가 실행되려고 했지만
메모리 부족
으로 일시 중단된 상태.
종료 상태(terminated)
메모리
와 CPU 소유권
을 모두 놓고 가는 상태.
- 자연스럽게 종료되는 것도 있지만, 부모 프로세스가 자식 프로세스를 강제시키는
비자발적 종료(abort)
로 종료되는 것도 있음.
- 자식 프로세스에 할당된 자원의 한계치를 넘어섰을 때
- 부모 프로세스가 종료되었을 때
- process, kill 등 여러 명령어로 프로세스를 종료할 때
3.3.3 프로세스의 메모리 구조
스택과 힙
- 스택과 힙은
동적 할당
된다.
- 동적 할당 : 런타임 단계에서 메모리를 할당받는 것
- 스택
- 지역 변수, 매개변수, 실행되는 함수에 의해 늘어나거나 줄어드는 메모리 영역
- 함수가 호출될 때마다 호출될 때의 환경 등 특정 정보가 스택에 계속해서 저장됨.
- 재귀 함수가 호출된다고 했을 때 새로운 스택 프레임이 매번 사용되기 때문에 함수 내의 변수 집합이 해당 함수의 다른 인스턴스 변수를 방해하지 않는다.
- 힙
- 동적으로 할당되는 변수들을 담는다.
malloc()
, free()
함수를 통해 관리할 수 있다
- 동적으로 관리되는 자료 구조의 경우 힙 역영을 사용
- ex)
vector
는 내부적으로 힙 영역을 사용
데이터 영역과 코드 영역
정적 할당
되는 영역
- 정적 할당 : 컴파일 단계에서 메모리를 할당하는 것
- 데이터 영역은
BSS segment
와 Data segment
, code/text segment
로 나뉘어 저장된다.
- BSS segment
- 전역 변수 또는 static, const로 선언됨
- 0으로 초기화 또는 어떠한 값으로도 초기화 되어 있지 않은 변수들이 이 메모리 영역에 할당
- Data segment
- 전역 변수 또는 staic, const로 선언됨
- 0이 아닌 값으로 초기화된 변수가 이 메모리 영역에 할당
- code segment
3.3.4 PCB
- Process Control Block
- 운영체제에서 프로세스에 대한 메타데이터를 저장한 '데이터'
- 프로세스 제어 블록이라고도 함
- 프로세스가 생성되면 운영체제는 해당 PCB를 생성한다.
프로그램이 실행되면 프로세스가 생성
되고 프로세스 주소 값들에 앞서 설명한 스택, 힙 등의 구조를 기반으로 메모리가 할당
된다. 그리고 이 프로세스의 메타데이터들이 PCB
에 저장되어 관리된다.
PCB
는 프로세스의 중요한 정보를 포함하고 있기 때문에 일반 사용자가 접근하지 못하도록 커널 스택의 가장 앞부분에서 관리된다.
메타데이터 : 데이터에 관한 구조화된 데이터
이자 데이터를 설명하는 작은 데이터
. 대량의 정보 가운데에서 찾고 있는 정보를 효율적으로 찾아내 이용하기 위해 일정한 규칙에 따라 콘텐츠에 대해 부여되는 데이터이다.
PCB의 구조
- 프로세스 스케줄링 상태
- 프로세스 ID
- 프로세스 권한
- 프로그램 카운터
- CPU 레지스터
- CPU 스케줄링 정보
- 계정 정보
- I/O 상태 정보
컨텍스트 스위칭
- PCB를 교환하는 과정
- 한 프로세스에 할당된 시간이 끝나거나 인터럽트에 의해 발생
- 컴퓨터는 프로그램들을 동시에 실행하는 것처럼 보이지만, 실행되고 있는 프로세스는 단 한개이며 다른 프로세스와의
컨텍스트 스위칭
이 아주 빠르게 실행되기 때문에 동시에 구동되는 것처럼 보인다.
(참고 : 현대에는 멀티코어 CPU로 인해 한 시점에 한 개의 프로그램이라는 설명을 틀린 설명이지만, 컨텍스트 스위칭을 설명할 때는 싱글코어
를 기준으로 설명한다.
- 프로세스 A 실행하다 멈춤
- 프로세스 A의 PCB를 저장
- 프로세스 B를 로드하여 실행
- 프로세스 B의 PCB를 저장
- 프로세스 A의 PCB를 로드
컨텍스트 스위칭이 일어날 때 유휴 시간(idle time)
이 발생한다. 추가로 드는 비용으로 캐시미스
가 있다.
비용:캐시미스
컨텍스트 스위칭이 일어날 때, 프로세스가 가지고 있는 메모리 주소가 그대로 있으면 잘못된 주소 변환이 생기므로 캐시클리어
과정을 겪게 되고 이로 인해 캐시미스
가 발생한다.
스레드에서의 컨텍스트 스위칭
스레드에서도 컨텍스트 스위칭이 일어난다. 스레드는 스택 영역을 제외한 모든 메모리를 공유하기 때문에 스레드 컨텍스트 스위칭
의 경우 비용과 시간이 적게
걸린다.
3.3.5 멀티프로세싱
- 여러 개의
프로세스
, 즉 멀티프로세스
를 통해 동시에 두 가지 이상의 일을 수행할 수 있는 것.
- 하나 이상의 일을 병렬로 처리 가능
- 특정 프로세스의 메모리, 프로세스 중 일부에 문제가 생겨도 다른 프로세스를 이용해 처리할 수 있어 신뢰성이 높다
웹 브라우저
웹 브라우저는 멀티프로세스 구조를 가지고 있다.
IPC
멀티프로세스는 IPC(Inter Process Communication)가 가능하다.
- IPC : 프로세스끼리 데이터를 주고받고 공유 데이터를 관리하는 메커니즘
- IPC 예) 클라이언트와 서버. 클라이언트는 데이터를 요청하고 서버는 클라이언트 요청에 응답하는 것
- IPC의 종류 : 공유 메모리, 파일, 소켓, 익명 파이프, 명명 파이프, 메시지 큐. 모두 메모리가 완전히 공유되는 스레드보다 속도가 떨어진다.
공유 메모리(shared memory)
여러 프로세스에 동일한 메모리 블록에 대한 접근 권한이 부여되어 프로세스가 서로 통신할 수 있도록 공유 메모리를 생성해 통신하는 것.
- 기본적으로 각 프로세스의 메모리를 다른 프로세스가 접근할 수 없음
- 하지만 공유 메모리를 통해 여러 프로세스가 하나의 메모리를 공유할 수 있음
- IPC 방식 중 어떠한 매개체를 통해 데이터를 주고받는 것이 아닌 메모리 자체를 공유하기 때문에 불필요한 데이터 복사의 오버헤드가 발생하지 않아 가장 빠름
- 같은 메모리 영역을 여러 프로세스가 공유하기 때문에 동기화 필요
파일
- 디스크에 저장된 데이터 또는 파일 서버에서 제공한 데이터.
- 이를 기반으로 프로세스 간 통신을 한다
소켓
- 동일한 컴퓨터의 다른 프로세스나 네트워크의 다른 컴퓨터로 네트워크 인터페이스를 통해 전송하는 데이터.
- TCP와 UDP가 있음
익명 파이프(unamed pipe)
- 프로세스 간에 FIFO 방식으로 읽히는 임시 공간인 파이프를 기반으로 데이터를 주고받으며, 단방향 방식의 읽기 전용, 쓰기 전용 파이프를 만들어 작동하는 방식
- 부모, 자식 프로세스 간에만 사용 가능. 다른 네트워크상에서는 사용이 불가능하다
명명된 파이프(named pipe)
- 파이프 서버와 하나 이상의 파이프 클라이언트 간의 통신을 위한 명명된 단방향 또는 양방향 파이프
- 클라이언트/서버 통신을 위한 별도의 파이프 제공
- 여러 파이프 동시에 사용 가능
- 컴퓨터의 프로세스끼리 또는 다른 네트워크상의 컴퓨터와도 통신 가능
그림처럼 서버용 파이프
와 클라이언트용 파이프
로 구분해서 작동하며, 하나의 인스턴스를 열거나 여러 개의 인스턴스를 기반으로 통신한다.
메시지 큐
- 메시지를
큐(queue)
데이터 구조 형태로 관리하는 것
- 커널의 전역변수 형태 등
커널에서 전역적으로 관리
됨.
- 장점
- 다른 IPC 방식에 비해 사용 방법이 매우 직관적이고 간단
- 다른 코드의 수정 없이 단지 몇줄의 코드를 추가시켜 간단하게 메시지 큐에 접근할 수 있음
공유 메모리를 통해 IPC를 구현할 때 쓰기 및 읽기 빈도가 높으면 동기화 때문에 기능을 구현하는 것이 매우 복잡해지는데, 이때 대안으로 메시지 큐
를 사용하기도 한다.
3.3.6 스레드와 멀티스레딩
스레드
- 프로세스의 실행 가능한 가장 작은 단위
- 프로세스는 여러 스레드를 가질 수 있다.
프로세스 : 코드, 데이터, 스택, 힙을 각각 생성
스레드 : 코드, 데이터, 힙은 스레드끼리 서로 공유. 그 외 영역은 각각 생성
멀티스레딩
- 프로세스 내 작업을 여러 개의 스레드, 멀티스레드로 처리하는 기법.
- 장점
- 스레드끼리 서로 자원을 공유하기 때문에 효율성이 높음
- 예) 웹 요청을 처리할 때 새 프로세스를 생성하는 대신 스레드를 사용하는 웹 서버의 경우, 훨씬 적은 리소스를 소비. 또한 한 스레드가 blocked 되어도 다른 스레드는 running 상태일 수 있어 중단되지 않은 빠른 일처리가 가능하다.
- 동시성이 좋음(동시성 : 서로 독립적인 작업들을 작은 단위로 나누고 동시에 실행되는 것처럼 보여주는 것)
- 단점
- 한 스레드에 문제가 생기면 다른 스레드에도 영향을 끼쳐 스레드로 이루어져 있는 프로세스에 영향을 줄 수 있다.
멀티스레드의 예 : 웹 브라우저의 렌더러 프로세스. 메인스레드, 워커 스레드, 컴포지터 스레드, 레스터 스레드가 존재한다.
3.3.7 공유 자원과 임계 영역
공유 자원(shared resource)
- 시스템 안에서 각 프로세스, 스레드가 함께 접근할 수 있는 모니터, 프린터, 메모리, 파일, 데이터 등의 자원이나 변수
-경쟁 상태(race condition)
: 공유 자원을 두 개 이상의 프로세스가 동시에 읽거나 쓰는 상황. 동시에 접근을 시도할 때 접근의 타이밍이나 순서 등이 결괏값에 영향을 줄 수 있는 상태.
종선코인 100개가 있다고 할 때, 프로세스 A와 프로세스 B가 동시에 접근하여 타이밍이 서로 꼬여 정상 결괏값은 300인데 200이 출력된다.
임계 영역(critical section)
- 둘 이상의 프로세스, 스레드가 공유 자원에 접근할 때 순서 등의 이유로 결과가 달라지는 코드 영역.
- 임계 영역 해결 방법 :
뮤텍스
, 세마포어
, 모니터
- 세 가지 모두
상호 배제
, 한정 대기
, 융통성
이라는 조건을 만족한다.
잠금(lock)
은 이 방법의 토대가 되는 메커니즘이다.
- 예) 임계 영역을 화장실이하고 가정하면, A가 들어가 문을 잠근다. 그 다음 사람이 기다리다 A가 나오면 사용한다.
- 상호 배제 : 한 프로세스가 임계 영역에 들어갔을 때 다른 프로세스가 들어갈 수 없음
- 한정 대기 : 특성 프로세스가 영원히 임계 영역에 들어가지 못하면 안 됨
- 융통성 : 한 프로세스가 다른 프로세스의 일을 방해해서는 안 됨
뮤텍스(mutex)
- 프로세스나 스레드가 공유 자원을
lock()
을 통해 잠금 설정하고 사용한 후에 unlock()
을 통해 잠금 해제하는 객체.
- 잠금이 설정되면 다른 프로세스나 스레드는 잠긴 코드 영역에 접근할 수 없고 해제는 그와 반대이다.
잠금
또는 잠금 해제
라는 상태만 가진다.
세마포어(semaphore)
- 일반화된 뮤텍스.
- 간단한 정수 값과 두 가지 함수 wait(P 함수) 및 signal(V 함수)로 공유 자원에 대한 접근을 처리
- wait() : 자신의 차례가 올 때까지 기다리는 함수
- signal() : 다음 프로세스로 순서를 넘겨주는 함수
- 프로세스나 스레드가 공유 자원에 접근하면 세마포어에서 wait() 작업을 수행
- 프로세스나 스레드가 공유 자원을 해제하면 signal() 작업을 수행
- 세마포어에는 조건 변수가 없고 프로세스나 스레드가 세마포어 값을 수정할 때 다른 프로세스나 스레드는 동시에 세마포어 값을 수정할 수 없음
- 바이너리 세마포어
- 0과 1의 두 가지 값만 가질 수 있는 세마포어
- 구현의 유사성으로 뮤텍스를 바이너리 세마포어라고 할 수 있지만.. 엄밀히 말하자면 다르다.
- 뮤텍스 :
잠금 메커니즘
. 잠금을 기반으로 상호배제 일어남
- 세마포어 :
신호 메커니즘
. 신호를 기반으로 상호 배제가 일어남(노래 듣다가 전화오면 노래 중지되고 통화 인터페이스가 등장하는 것)
- 카운팅 세마포어
- 여러 개의 값을 가질 수 있는 세마포어
- 여러 자원에 대한 접근을 제어하는 데 사용
모니터
- 둘 이상의 스레드가 프로세스가 공유 자원에 안전하게 접근할 수 있도록 공유 자원을 숨기고 해당 접근에 대해 인터페이스만 제공.
- 그림처럼 모니터는
모니터큐
를 통해 공유 자원에 대한 작업들은 순차적으로 처리한다.
모니터
는 세마포어
보다 구현이 쉽다
모니터
에서 상호 배제는 자동이지만, 세마포어
에서는 상호 배제를 명시적으로 구현해야 한다.
3.3.8 교착 상태(deadlock)
- 두 개 이상의 프로세스들이 서로가 가진 자원을 기다리며 중단된 상태
ex) 프로세스 a가 프로세스 b의 어떤 자원을 요청할 때, b도 a가 점유하고 있는 자원을 요청하는 것.
교착 상태의 원인
- 상호 배제 : 한 프로세스가 자원을 독점하고 있으며 다른 프로세스들이 접근 불가능
- 점유 대기 : 특정 프로세스가 점유한 자원을 다른 프로세스가 요청하는 상태
- 비선점 : 다른 프로세스의 자원을 강제적으로 가져올 수 없음
- 환형 대기 : 프로세스 a는 프로세스 b의 자원을 요구하고, 프로세스 b는 프로세스 a의 자원을 요구하는 등 서로가 서로의 자원을 요구하는 상황
교착 상태 해결 방법
- 자원을 할당할 때 애초에 조건이 성립되지 않게 한다
- 교착 상태 가능성이 없을 때만 자원 할당되며, 프로세스당 요청할 자원들의 최대치를 통해 자원 할당 가능 여부를 파악하는
은행원 알고리즘
을 쓴다.
- 교착 상태가 발생하면 사이클이 있는지 찾아보고 이에 관련된 프로세스를 한 개씩 지운다
- 교착 상태는 매우 드물게 일어나기 때문에 이를 처리하는 비용이 더 커서 교착 상태가 발생하면 사용자가 작업을 종료한다. 현대 운영체제는 이 방법을 채택했다.
은행원 알고리즘 : 총 자원의 양과 현재 할당된 자원의 양을 기준으로 안정 또는 불안정 상태로 나누고 안정 상태로 가도록 자원을 할당하는 알고리즘
Reference
주홍철 작가님의 '면접을 위한 CS 전공지식 노트'를 기반으로 작성되었습니다.