프로세스와 스레드
프로세스
프로그램 ?
저장장치에 저장된 명령문의 집합체이다.
저장장치만 사용하는 수동적인 존재
프로세스 ?
실행 중인 프로그램이다.
즉, 하드디스크에 저장되어있던 프로그램이 메모리에 올라갔을 때 프로세스라고 부른다.
CPU, 메모리를 사용하며, 입출력도 한다. → 능동적인 존재
프로세스의 구조
코드 영역
자신을 실행하는 코드가 모여있는 부분
데이터 영역
전역 변수, 정적 변수(static) 가 저장되어있는 부분
스택 영역
지역변수, 함수 호출을 했을 때 필요한 데이터들이 저장된다.
힙 영역
동적으로 메모리를 할당하는데에 쓰인다.
프로그램의 컴파일 과정
(test.c) → 전처리기 → (test.i) → 컴파일러 → (test.s, 어셈블리어) → 어셈블러 → (test.o, 기계어) → 링커 → (test.exe)
→ test.exe를 실행시키면, 메모리에 올라가게된다. 이때부터 test.exe가 프로세스라고 불리게 된다. 이후는 운영체제에서 실행파일을 관리한다.
멀티프로그래밍과 멀티프로세싱
메모리 관점
유니 프로그래밍 = 메모리에 오직 하나의 프로세스만 올라온다.
멀티 프로그래밍 = 메모리에 여러개의 프로세스가 올라온다
CPU 관점
멀티 프로세싱 = CPU가 여러개의 프로세싱을 처리하는 것이다.
오늘날의 OS는 멀티 프로그래밍, 멀티 프로세싱이 공존한다. (시분할 시스템 이용)
과거의 OS는 유니 프로그래밍과 멀티 프로세싱이 공존했다. (스와핑 이용)
→ 스와핑 : 메모리에 있는 데이터를 다른 저장장치로 보내고, 다른 프로세싱을 메모리에 올려서 사용하는 것
PCB (Process Control Block)
운영체제의 역할 : 여러 개의 프로세스를 관리하고, 공평하게 실행시켜주는 것이다. 이를 위해 필요한게 PCB!
프로세스 실행과 PCB
프로세스가 만들어지면, 해당 프로세스의 정보를 저장하는 PCB를 만들고, 저장한다.
PCB는 연결리스트로 저장된다.
프로세스가 종료되면, 해당 프로세스의 PCB를 제거한다.
PCB의 구조
포인터 : 연결리스트 구조에 의한 공간
프로세스 상태 : 시분할 시스템을 위한 공간
프로세스 ID : 프로세스 식별을 위한 숫자
프로그램 카운터 : 다음에 실행 될 명령어의 주소를 저장 (CPU 재점유시 필요한 정보)
레지스터 정보 : 프로세스 실행 시 사용했던 레지스터 값을 저장 (CPU 재점유시 필요한 정보)
메모리 관련 정보 : 위치 정보, 경계 레지스터 값(메모리 침범 방지)
CPU 스케줄링 정보 : CPU스케줄링에 필요한 우선순위, 최종 실행시간, CPU 점유시간 등을 저장
기타 등등..
프로세스 상태
프로세스 ?
사용자가 프로그램을 실행시키면, 메모리에 프로그램이 올라가면서 프로세스가 생성된다.
오늘날의 운영체제는 메모리에 수 많은 프로세스가 올라간다. (멀티 프로그래밍)
CPU와 프로세스
시분할 시스템을 사용하는 OS는 여러 개의 프로세스를 돌아가면서 실행한다.
CPU는 한 순간에 하나의 프로세스만 처리할 수 있기 때문이다. (다만 속도가 매우 빨라서 사람이 보았을 때에는 동시에 실행하는 것처럼 느껴진다.)
프로세스의 상태
프로세스는 시분할 시스템을 위해 다섯가지의 상태를 가지고 있다.
→ 생성, 준비, 실행, 대기, 완료
생성 (new)
PCB를 생성하고 메모리에 프로그램 적재를 요청한 상태
적재를 승인받으면, 준비 상태가 된다.
준비 (ready)
CPU를 사용하기 위해 기다리는 상태
CPU 스케줄러에 의해 CPU가 할당된다.
대부분의 프로세스는 준비상태에 있다.
실행 (Running)
CPU를 할당받아 실행중인 상태
실행중인 프로세스의 최대 갯수 = CPU의 수 (CPU는 하나의 일만 할 수 있으니까)
부여된 시간만큼 사용할 수 있으며, 시간 초과 시 할당된 CPU를 빼앗긴다
→ 준비상태로 돌아간다.
대기 (waiting)
입출력이 완료될 때까지 기다리는 상태
입출력 작업이 완료되면, CPU 할당 기회를 부여받는다. (대기 종료 후 준비 상태로)
완료 (terminated)
프로세스가 종료된 상태
사용했던 메모리를 제거하고, 생성된 PCB를 제거한다.
컨텍스트 스위칭 (context switching)
컨텍스트 스위칭 ?
프로세스를 실행하는 중에, 다른 프로세스를 실행하기 위해 필요한 작업
실행 중인 프로세스 상태를 저장하고, 다른 프로세스의 상태 값으로 교체하는 작업이다.
컨텍스트 스위칭이 일어날 때, PCB의 내용이 변경된다.
실행 중인 프로세스의 작업 내용을 PCB에 저장하고, 실행 될 프로세스의 PCB의 내용으로 CPU가 세팅된다.
변경되는 값 = 프로세스 상태, 프로그램 카운터, 각종 레시트터 값들 (레지스터 정보, 메모리 관련 정보 등)
예시
Process A가 실행 중이다. 이때 CPU 점유 시간이 초과되었다.
운영체제가 이를 판단하여 인터럽트를 발생시킨다.
Process A는 하던 일을 멈추고, 현 CPU 레지스터의 값을 PCB A에 저장한다.
Process B를 참조하여 CPU 레지스터 값을 세팅한다.
프로그램 카운터를 보고 Process B의 명령어를 실행한다.
Process B의 점유 시간이 끝나면, 다시 컨텍스트 스위칭을 진행한다.
⇒ 결론 : 메모리에 있는 모든 프로세스들은 컨텍스트 스위칭을 한다.
컨텍스트 스위칭을 하는 이유
CPU 점유 시간의 초과
입출력 요청의 발생
다른 종류의 인터럽트 발생 등
프로세스 생성과 종료
프로세스의 생성 과정
실행파일이 실행되면, 운영체제는 코드 영역과 데이터 영역을 로드하고, 빈 스택과 빈 힙을 만들어 공간을 확보한다. 또한 해당 프로세스를 관리하기 위한 PCB를 만들어 값을 초기화한다.
운영체제가 부팅되고, 0번 프로세스가 생성될 때 딱 한 번만 실행된다.
나머지 모든 프로세스는 0번 프로세스를 복사해서 사용하게 된다. ⇒
fork()
함수 이용 (생성보다 복제가 더 빠르기 때문이다)자식 프로세스는 부모 프로세스의 코드, 데이터, 힙, 스택, PCB를 모두 복사하게 된다. 이후
execlp()
를 이용하여 원하는 값으로 덮어쓴다.
자식 프로세스와 부모 프로세스 중 먼저 실행되는 것은 운영체제의 결정에 따르게 된다.
예시
부모 프로세스가 먼저 실행된다고 가정한다.
8번 줄에서 부모 프로세스는 fork의 실행으로 1을 반환받아 15번 라인이 실행된다.
이후 17번의 wait이 실행되며, 자식 프로세스의 종료를 기다리게 된다. (시스템 함수임)
이수 자식 프로세스가 실행되며, fork의 실행으로 0을 받아 12번째 줄이 실행되어 인터넷 브라우저가 열린다.
정상적으로 코드가 실행되어 exit()함수는 실행되지 않는다. 자식 프로세스가 종료되어 부모프로세스가 실행된다.
이후 부모 프로세스는 자식 프로세스를 완전히 종료하며 18번 줄이 실행되며, exit()으로 프로세스 종료를 알린다.
좀비 프로세스 ?
부모 프로세스는 자식 프로세스의 exit status를 읽어 자식 프로세스를 정리한다. (실패시에 -1을 리턴, 성공은 반환하지 않음)
만약 부모가 먼저 종료 되거나, 자식이 비정상적으로 종료되어 exit() 신호를 주지 못할 수 있다.
이 경우 exit status를 읽지 못해 메모리에 프로세스가 계속 존재할 수 있다. 이를 좀비 프로세스라고 한다.
컴퓨터를 오래 켜두었을 때 느려지는 이유가 메모리에 프로세스가 많아서일 수도 있지만, 좀비프로세스가 메모리를 많이 차지해질 수 있다.
이에 컴퓨터를 껐다가 켰을 때 빨라지는 이유는 메모리가 초기화되어서이기 때문이다.
쓰레드 (Thread)
Thread는 왜 필요한가?
운영체제가 작업을 처리하는 단위는 프로세스였다.
사용자가 운영체제에게 작업을 요청하면, 그만큼 프로세스의 수가 늘어났다.
그런데 프로세스에 뭐가 있었지 ? → 코드 데이터 힙 스택 PCB까지!!
즉, 프로세스의 수가 많아지면 그만큼 저 영역도 만들어줘야하니까 매우 무거워진다는 말!!
Thread가 뭔데?
스레드는 프로세스 내에 존재하는 것으로, 하나의 프로세스 안에 1개 이상이 존재할 수 있다.
스레드들은 하나의 프로세스 안에서 PCB, 코드, 데이터, 힙을 공유하게 된다. (스택은 공유하지 않고, 스레드마다 하나씩 가진다)
스레드가 여러개 있으니 id를 통해 구분했고, 스레드를 관리하기 위해 스레드 컨트롤 블럭이 생겼다.
⇒ 운영체제의 관점에서도 스레드를 구분할 수 있으니 스레드를 관리할 수 있게 되었다.
⇒ 운영체제가 관리하는 단위 = 프로세스 내의 스레드가 되었다.
프로세스와 스레드의 장단점
안정성
프로세스가 더 우세하다.
프로세스는 독립적이기 때문에 다른 프로세스의 영향을 받지 않는다.
스레드는 하나의 프로세스에 종속적이기 때문에, 하나의 프로세스에 문제가 생기면 모든 스레드가 영향을 받는다. (데이터 영역의 공유)
성능 측면 (속도 및 자원)
스레드가 더 우세하다.
각각의 프로세스는 고유한 자원을 가지고 있다.
이에 프로세스 간 통신이 필요한 경우, IPC 통신을 통해 자원을 공유해야하는데 이는 오버헤드가 크고, 속도가 느리다.
스레드는 스택을 제외한 모든 영역을 공유한다.
오버헤드가 적고, 공유가 쉽다.
하지만 공유하는 공간에서 문제가 발생할 수 있다. (프로세스 동기화)
Last updated