[10-1] 프로세스 개요
프로세스 직접 확인하기
컴퓨터가 부팅되는 순간부터 수많은 프로세스들이 실행됩니다. 윈도우에서는 작업 관리자의 [프로세스] 탭에서 확인할 수 있고, 유닉스 체계의 운영체제에서는 ps 명령어로 확인할 수 있습니다. (%ps -ef) 실제로 확인해보면, 여러분이 실행한 프로세스 외에도 알 수 없는 여러 프로세스가 실행되고 있는 것을 볼 수 있습니다. 사용자가 보는 앞에서 실행되는 프로세스를 포그라운드 프로세스라고 하고, 사용자가 볼수 없는 뒤편에서 실행되는 프로세스를 백그라운드 프로세스라고 합니다. 사용자와 상호작용 없이 묵묵히 정해진 일만 수행하는 백그라운드 프로세스를 유닉스 체계에서는 데몬이라고 부릅니다.
프로세스 제어 블록
모든 프로세스는 실행을 위해 CPU를 필요로 하지만, CPU 자원은 한정되어 있습니다. 즉 모든 프로세스가 CPU를 동시에 사용할 수는 없습니다. 그렇기에 프로세스들은 돌아가며 한정된 시간만큼만 CPU를 이용합니다. 운영체제는 빠르게 번갈아 수행되는 프로세스의 실행 순서를 관리하고, 프로세스에 CPU를 비롯한 자원을 배분합니다. 이를 위한 운영체제는 프로세스 제어 블록(PCB)을 이용합니다. PCB에 담기는 정보는 운영체제마다 다르지만, 대표적으로는 아래와 같습니다.
프로세스 ID(PID) : 특정 프로세스를 식별하기 위해 부여하는 고유한 번호입니다.
레지스터 값 : 프로세스는 자신의 실행 차례가 돌아오면 이전까지 사용했던 레지스터의 중간값들을 모두 복원합니다.
프로세스 상태 : 현재 프로세스가 입출력장치를 사용하기 위해 기다리고 있는지, CPU 사용을 위해 기다리고 있는 상태인지 등의 정보입니다.
CPU 스케줄링 정보 : 프로세스가 언제, 어떤 순서로 CPU를 할당 받을 지에 대한 정보도 PCB에 기록됩니다.
메모리 관리 정보 : 프로세스마다 메모리에 저장된 위치가 다릅니다. 그래서 PCB에는 프로세스가 어느 주소에 저장되어 있는지에 대한 정보가 있어야 합니다.
문맥 교환
하나의 프로세스에서 다른 프로세스로 실행 순서가 넘어가면 어떤 일이 일어날까요? 가령 프로세스 A가 운영체제로부터 CPU를 할당받아 실행되다가 시간이 다 되어 프로세스 B에 CPU 사용을 양보한다고 가정해봅니다. 이런 상황에서 바로 직전까지 실행되던 프로세스 A는 프로그램 카운터를 비롯한 각종 레지스터 값, 메모리 정보, 실행을 위해 열었던 파일이나 사용한 입출력장치 등 지금까지의 중간 정보를 백업해야 합니다. 그래야만 다음 차례가 왔을 때 이전까지 실행 했던 내용에 이어 다시실행을 재개할 수 있습니다. 이러한 중간 정보, 즉 하나의 프로세스 수행을 재개하기 위해 기억해야 할 정보를 문맥이라고 합니다. 새로운 프로세스를 실행하기 위핸 문맥을 PCB로부터 복구하여 새로운 프로세스를 실행하는 것을 문맥 교환이라고 합니다.
프로세스의 메모리 영역
코드 영역 (텍스트 영역) : 기계어로 이루어진 명령어가 저장됩니다. 코드 영역에는 데이터가 아닌 CPU가 실행할 명령어가 담겨 있기 때문입니다. 다시 말해 코드 영역은 읽기 전용 공간입니다.
데이터 영역 : 잠깐 썼다가 없앨 데이터가 아닌 프로그램이 실행되는 동안 유지할 데이터가 저장되는 공간입니다. 이런 데이터로는 전역 변수가 대표적입니다. 프로그램이 실행되는 동안 유지되며, 프로그램 전체에서 접근할 수 있는 변수 정도로만 이해하고 12장에서 다시 설명됩니다.
힙 영역 : 프로그래머가 직접 할당할 수 있는 저장 공간입니다.
스탭 영역 : 데이터를 일시적으로 저장하는 공간입니다.
[10-2] 프로세스 상태와 계층 구조
프로세스 상태
여러분이 컴퓨터를 사용할 때 여러 프로세스들이 빠르게 번갈아 가면서 실행된다고 하였습니다. 그 과정에서 하나의 프로세스는 여러 상태를 거치며 실행됩니다. 그리고 운영체제는 프로세스의 상태를 PCB를 통해 인식하고 관리합니다. 프로세스가 가질 수 있는 대표적인 상태는 아래와 같습니다.
생성 상태 : 프로세스가 생성 중인 상태. 이제 막 메모리에 적재되어 PCB를 할당 받은 상태
준비 상태 : 당장이라고 CPU를 할당 받아 실행할 수 있지만, 아직 차례가 아니라 기다리고 있는 상태
실행 상태 : CPU를 할당받아 실행 중인 상태.
대기 상태 : 입출력 장치를 사용하는 경우, 입출력 작업이 CPU에 비해 처리 속도가 느리기에 입출력 작업이 끝날 때까지 기다려야 하는데 그애를 대기 상태(blocked)라고 부릅니다.
종료 상태 : 프로세스가 종료된 상태.
프로세스 생성 기법
부모 프로세스를 통해 생성된 자식 프로세스들은 복제와 옷 갈아입기를 통해 실행됩니다. 조금 더 정확하게, 부모 프로세스는 fork를 통해 자신의 복사본을 자식 프로세스로 생성해내고, 만들어진 복사본은 exec를 통해 자신의 메모리 공간을 다른 프로그램으로 교체합니다. fork와 exec에 대해 조금 더 자세히 알아본다면, fork와 exec는 시스템 호출입니다. fork를 통해 복사본이 만들어진 뒤에 자식 프로세스는 exec 시스템 호출을 통해 새로운 프로그램으로 전환됩니다. exec는 자신의 메모리 공간을 새로운 프로그램으로 덮어쓰는 시스템 호출입니다.
예를 들어, 사용자가 bash 셀에서 ls라는 명령어를 쳤다고 가정해봅시다. 셀 프로세스는 fork를 통해 자신과 동일한 프로세스를 생성하고, 그로부터 탄생한 자식 프로세스는 exec를 통해 ls 명령어를 실행하기 위한 프로세스로 전환되어 실행됩니다.
[p304 확인문제]
[10-3] 스레드
스레드는 실행 단위입니다. 조금 더 정확하게 표현하자면, 스레드란 프로세스를 구성하는 실행의 흐름 단위입니다. 스레드를 이용하면, 하나의 프로세스에서 여러 부분을 동시에 실행할 수 있습니다.
프로세스와 스레드
전통적인 관점에서 보면 하나의 프로세스는 한 번에 하나의 일만을 처리했습니다. 앞선 절에서도 한 번에 하나의 작업을 처리하는 프로세스를 상정했었습니다. 기존에는 '단일 스레드 프로세스'라고 볼 수 있다면, 스레드라는 개념이 도입되면서 하나의 프로세스가 한 번에 여러 일을 동시에 처리할 수 있게 되었습니다. 즉, 프로세스를 구성하는 여러 명령어를 동시에 실행할 수 있게 된 것입니다. 즉 하나의 프로세스 내에서 각기 다른 스레드 ID, 프로그램 카운터 값을 비롯한 레지스터 값, 스택으로 구성됩니다. 여기서 중요한 점은 프로세스의 스레드들은 실행에 필요한 최소한의 정보만을 유지한 채 프로세스 자원을 공유하며 실행된다는 점입니다.
멀티프로세스와 멀티스레드
동일한 작업을 수행하는 단일 스레드 프로세스 여러 개를 실행한느 것과 하나의 프로세스를 여러 스레드로 실행하는 것은 무엇이 다를까?
예를 들어 "hello.os"를 화면에 출력하는 간단한 프로그램이 있다고 해 봅시다. 이 프로그램을 세 번 fork하여 실행하면 화면에는 "hello.os"가 세 번 출력됩니다. 이 프로그램 내에 "hello.os"를 출력하는 스레드를 세 개 만들어 실행해도 화면에는 "hello.os"가 세 번 출력 됩니다. 이 둘의 차이점은 무엇일까? 바로, 프로세스끼리는 자원을 공유하지 않지만, 스레드끼리는 프로세스 내의 자원을 공유한다는 점입니다.
(1) 여러 프로세스로 병행 실행
메모리
"hello.os" 출력 프로세스 ~실행 흐름~ |
"hello.os" 출력 프로세스 ~실행 흐름~ |
"hello.os" 출력 프로세스 ~실행 흐름~ |
(2) 여러 스레드로 병행 실행
메모리
"hello.os" 출력 프로세스 |
~실행 흐름~ ~실행 흐름~ ~실행 흐름~ |
위처럼 큰 차이가 있습니다. 프로세스 여러 개로 실행하는 것은 어쩌면 자원 낭비처럼 보입니다. 반면에 여러 스레드로 구성하는 것이 효율적이게 보이지만, 여러 스레드로 작업시에 하나의 스레드에서 문제가 발생하면, 프로세스 내의 다른 스레드에 모두 영향을 미칠 수 있다는 리스크가 있습니다.
'computer science' 카테고리의 다른 글
[#혼공] 혼자 공부하는 컴퓨터 구조+운영체제 [Chapter.09] (0) | 2023.08.05 |
---|---|
동시성과 병렬성 (0) | 2023.08.04 |
코루틴 (0) | 2023.08.03 |
동기와 비동기 (0) | 2023.08.02 |
CPU 바운드, I/O bound, 블로킹 (0) | 2023.08.02 |