우리가 자주 사용하는 크롬, 카카오톡, 노션 등은 프로그램입니다. 프로그램은 일련의 작업을 포함하고 있는 코드 파일이며 이는 하드디스크에 저장되어 있습니다. 프로그램을 조금 복잡하게 설명했지만 단순하게 말하면 코드 덩어리를 의미합니다. 사용자가 프로그램(코드 파일)을 실행하면 운영체제는 하드디스크에 저장된 코드 파일을 메모리에 할당하고 스케쥴링을 통해 메모리에 올라간 프로그램을 CPU가 실행하면서 사용자는 원하는 작업을 할 수 있습니다. 이와 같이 프로그램이 시스템 자원을 얻고 실행 중인 상태를 프로세스 라고 합니다. 이번 글에서는 프로세스
에 대해서 자세하게 알아보겠습니다.
프로세스를 좀 더 간단하게 설명하면 프로그램이 돌아가고 있는 상태를 의미합니다. 다른 말로는 컴퓨터의 작업 단위라고도 합니다. 프로세스는 윈도우에서는 “작업관리자”를 통해서 볼 수 있고 mac에서는 “활성 상태 보기”를 통해 볼 수 있습니다.
프로세스는 독자적인 메모리를 운영체제로부터 할당받으며 메모리 구조는 4가지 영역을 가지고 있습니다. (코드, 데이터, 스택, 힙)
✏️ 스택(Stack)
✏️ 힙(Heap)
✏️ 데이터(Data)
✏️ 코드(Code)
이전 포스트(주소)를 보면 멀티프로그래밍 시스템과 시분할 시스템(멀티 테스트)의 경우 CPU가 여러 프로그램(프로세스)들은 전환해 나가면서 CPU의 사용률을 높이고 마지 동시에 프로그램이 동작하는 것처럼 느껴지게 했습니다. 이 과정에서 CPU가 하나의 작업을 온전히 끝내고 다른 작업으로 넘어가면 좋겠지만 작업 중간에 I/O나 인터럽트가 발생하면 진행중인 작업을 멈추고 다른 프로세스로 전환됩니다. 이후 원래 프로세스으로 돌아와 이어서 작업하기 위해서는 프로세스 전환이 발생하기 전에 정보를 저장해두고 있어야 하는데 이 정보를 프로세스 문맥
이라고 합니다.
프로세스 문맥은 “하드웨어 문맥”, “커널상의 문맥”으로 구분할 수 있습니다. “하드웨어 문맥”은 CPU가 현재 어디까지 작업을 진행했는지 나타내는 것으로 ProgramCounter와 각종 레지스터에 저장하고 있는 정보들을 의미합니다. “커널상의 문맥”은 프로세스를 제어하기 위한 자료구조(PCB)를 의미합니다.
💡문맥 교환(Context switching)
문맥 교환은 기존에 작업하고 있는 프로세스에서 다른 프로세스로 전환되는 과정으로 문맥 교환이 발생하면 기존에 작업 중인 프로세스의 내용을 저장하고 작업할 프로세스의 내용이 불러옵니다.
프로세스 제어 블록(PCB)는 운영체재 내에서 프로세스를 관리하기 위해 프로세스 마다 정보를 가지고 있는 커널 내의 자료 구조입니다. 운영체제는 PCB를 통해서 프로세스 간의 문맥교환, 통신, 스케줄링 및 자원관리를 진행합니다.
항목 | 설명 | 활용 예시 |
---|---|---|
프로세스 ID (PID) | 프로세스를 식별하는 고유 번호. | 프로세스를 검색하거나 프로세스 간 통신(IPC) 시 사용. |
프로세스 상태 | 준비, 실행, 대기, 종료 등 현재 상태. | CPU 스케줄러가 어떤 프로세스를 실행할지 결정. |
CPU 레지스터 | CPU의 현재 상태를 저장 (프로그램 카운터, 스택 포인터 등). | 문맥 전환 시 저장 및 복원하여 프로세스 실행을 이어감. |
메모리 관리 정보 | 페이지 테이블, 세그먼트 테이블, 메모리 경계 등. | 프로세스가 점유하는 메모리 추적 및 충돌 방지. |
열려 있는 파일 목록 | 프로세스가 접근 중인 파일의 정보. | 파일 입출력 관리 및 자원 해제. |
신호 처리 정보 | 프로세스가 받을 신호와 처리 방식. | 프로세스 간 통신(IPC) 및 예외 처리. |
우선순위 | 프로세스의 실행 우선순위. | 스케줄러가 어떤 프로세스를 먼저 실행할지 결정. |
프로세스는 다양한 상태를 가지고 있고 운영체제는 해당 정보를 통해 프로세스에게 CPU를 할당할지 말지 결정합니다. 프로세스의 각 상태에 대해서 알아보고 어떤 상황에서 상태가 변환되는지 알아보겠습니다.
상태 | 설명 |
---|---|
New | 프로세스가 생성된 상태로, 메모리를 할당 받지 못한 상태 |
Ready | 실행 대기 상태로, 프로세스가 CPU 할당을 기다리고 있음. |
Running | CPU를 점유하여 실행 중인 상태. |
Waiting/Blocked | I/O 작업 등 외부 이벤트를 기다리고 있는 상태. (cpu를 얻더라도 바로 작업이 수행되지 못한 상태) |
Terminated | 프로세스가 실행을 완료하고 종료된 상태. |
상태 변화가 일어나는 과정
프로그램은 단일 프로세스로 처리하게 되면 효율성이 떨어지는 부분이 발생합니다. 예를 들면 I/O 작업으로 인해서 프로세스가 대기상태로 들어가게 되면 해당 프로그램 내 다른 작업을 처리할 수 없게 됩니다.(하나의 프로세스가 모든 작업을 처리해야하는 상황인데 I/O를 대기하고 있기 때문) 이와 같은 문제를 해결하고자 프로세스를 여러개 생성해서 처리하는 방식이 등장하는데 이를 멀티 프로세스라고 합니다.
멀티 프로세스의 구조를 보면 하나의 프로세스에서 여러 개의 프로세스를 생성해 다중 프로세스를 구성합니다. 유닉스 계열에서는 프로세스가 시스템 호출 중 fork()를 통해 프로세스를 생성하며 생성을 호출한 프로세스를 부모 프로세스라고 하고 생성된 프로세스를 자식 프로세스라고 합니다. 부모 프로세스는 자식 프로세스의 PID를 알 수 있으며 자식 프로세스는 PPID를 통해부모의 프로세스의 ID를 알 수 있습니다.
부모 프로세스와 자식 프로세스는 초기에는 같은 메모리 정보를 가지고 있지만 외부의 요청으로 변화가 발생하게 되면 메모리의 복사가 발생하고 이후부터는 부모와 자식은 각각의 독립적인 메모리 공간을 가지게 되어 서로 독립적으로 동작하게 됩니다.
✏️ 장점
✏️ 단점
💡 여러 개의 프로세스는 어떻게 통신할까?
하나의 큰 작업을 처리할 때에는 하나의 프로세스가 처리하는 것이 아닌 여러 프로세스가 처리해야하는 상황이 발생합니다. 이 때 두 프로세스가 통신하기 위해서는 IPC 기술을 활용합니다. IPC 방식에는 메세지 전달 방식과 메모리 공유 방식이 있습니다.메세지 전달 방식
- 커널을 통해 메세지를 전달하는 방식
- 시스템 콜이 필요하면 잦은 통신이 발생하면 오버헤드가 발생
- pipe, signal, message queueing, socket 방식 등
공유 메모리 방식
- 공유 메모리를 구축해 여러 프로세스가 같은 데이터를 주고 받는 방식
- 커널을 거치지 않기에 통신이 자유롭고 속도가 빠름
- 자원을 서로 공유하기에 동기화 문제가 발생
- 세마포어를 이용한 방식 등