본문 바로가기
스터디/CS & Network

프로세스 (Process)

by 헤콩 2021. 5. 19.
반응형

오늘의 주제는 프로세스!!

대부분 '프로세스와 스레드' 라는 주제의 글을 많이 볼 수 있는데, 저는 일단 프로세스를 공부하면서 연계되는 모든 과정을 최대한 나무처럼 뻗어나가면서 알아보려고 합니다.

 

즉, 제목은 프로세스 지만.... 내용을 보면.. 프로세스가 뭔지부터 시작해서 프로세스의 상태, PCB, fork() 등등.... 까지 들어갈 예정이랍니다. 정리해보면 아래 정도를 다룰 수 있겠네요😂

 

어우 진짜 CS는 알면 알수록 어디가 끝인지 모르겠지만 일단 오늘은 저정도만 보겠습니다. 아래 내용은 쉽게 배우는 운영체제 라는 책을 참고해서 작성했습니다 :)

 

 

 

프로그램? 프로세스? 뭐가 다른거야?

일단 프로그램은 하드디스크 같은 저장장치에 저장되어있는 정적인 상태를 말합니다. 어떠한 데이터를 사용해서 어떤 작업을 할지 그 절차를 작성해놓은거죠. 그리고 프로세스는 그 프로그램이 실행을 위해 메모리에 올라온 동적인 상태를 말합니다. 즉, 실행되고 있는 프로그램을 프로세스라고 하는거죠.

 

운영체제에서 프로세스는 하나의 작업 단위로써, 태스크(task) 라고도 불립니다.

 

운영체제가 프로그램을 메모리의 적당한 위치로 가져오면 그와 동시에 프로세스 제어 블록 (Process Control Block, PCB) 라는 걸 만드는데, 이 PCB 안에 프로세스를 실행하기 위한 다양한 정보가 들어있습니다. 즉, 어떤 프로그램이 프로세스가 되었다는 것은 운영체제로부터 프로세스 제어 블록을 받았다는 의미 입니다.

 

 

 

말 나온 김에 PCB에 대해 잠깐 살펴볼게요

 

"PCB는 운영체제가 프로세스를 표현한 것이다."

 

PCB는 운영체제가 프로세스를 제어하기 위해 정보를 저장해놓는 곳으로, 프로세스의 상태정보를 저장하는 구조체 입니다. 프로세스 상태 관리문맥교환 (Context Switching) 을 위해 필요한 것이죠. PCB가 프로세스의 중요한 정보를 포함하고 있기 때문에, 일반 사용자가 접근하지 못하도록 보호된 메모리 영역 안에 남습니다. 일부 운영체제에서는 커널 스택의 처음에 위치한다고 해요!

 

따라서 PCB에는 프로세스에 대한 다양한 정보가 있습니다.

 

PCB를 연결하여 준비 상태 혹은 대기 상태의 큐를 구현할 때 사용할 포인터.

프로세스가 현재 어떤 상태에 있는지.

운영체제 내에 있는 여러 프로세스를 구별하기 위한 프로세스 구분자 (PID).

다음에 실행될 명령어의 위치를 가리키는 프로그램 카운터.

계정 정보, CPU 할당 시간, CPU 사용 시간 등등...

 

왼쪽 그림과 같은 정보들을 가지고 있어요!

 

 

 

 

PCB는 Linked List 방식으로 관리됩니다. PCB List Head에 PCB들이 생성될 때마다 붙게 되는데, 주소값으로 연결이 되기 때문에 삽입과 삭제가 용이합니다.

 

 

좀 전에 PCB는 Context Switching 할 때 필요하다고 했죠?

그래서 Context Switching에 대해 살짝 설명하자면, CPU를 차지하던 프로세스가 나가고 새로운 프로세스를 받아들이는 작업을 뜻합니다. 따라서 문맥 교환을 할 때는 나가는 프로세스 P1의 현재 상태를 P1의 PCB에 저장하고, 새롭게 들어오는 프로세스 P2의 PCB로부터 P2의 상태를 얻어와 P2를 실행시키는 과정을 겪게 되어요!

문맥 교환의 과정

 

  • I/O request (입출력 요청)
  • time slice expired (CPU 사용시간 만료)
  • fork a child (자식 프로세스 생성)
  • wait for an interrupt (인터럽트 처리 대기)

Context Switching은 위와 같은 상황에서 발생할 수 있습니다. 그리고 이렇게 Context Switching 하는 과정에서 발생한 시간과 메모리를 Context Switching Overhead라고 합니다. Context Switching 때 해당 CPU는 아무런 일을 하지 못하기 때문에 Context Switching이 잦아지면 오히려 오버헤드가 발생해서 효율이 떨어질 수 있습니다!!

 

 

 

아니, Context Switching하면서 프로세스 상태가 변한다는데 그 상태가 뭐예요

그럼 다시 프로세스로 돌아가서 프로세스의 상태에 대해 알아볼게요 🌝

 

원래 일괄 작업 시스템에서는 단지 생성 (create) - 실행 (run) - 완료 (terminate) 의 상태만 있어도 괜찮았어요. 하지만 시분할 시스템에서는 CPU를 얻어 실행중인 프로세스가 중간에 다른 프로세스에게 CPU에 넘겨주는 일이 빈번하다보니, 좀 더 복잡한 상태를 가지고 있습니다.

 

1️⃣ 생성 (create) : 프로세스가 메모리에 올라와 실행준비를 완료한 상태. 프로세스를 관리하는 데 필요한 PCB 생성

2️⃣ 준비 (ready) : 생성된 프로세스가 CPU를 얻을 때까지 기다리는 상태. CPU가 하나인 컴퓨터에서는 한 번에 하나의 프로세스만 실행할 수 있기 때문에 자기 실행 순서가 될 때까지 준비 상태에서 기다려야 합니다.

PCB는 준비 큐 (Ready Queue) 에서 기다리며 CPU 스케줄러에 의해 관리되고, CPU 스케줄러는 준비 큐를 몇 개 운영할지, 어떤 프로세스의 PCB를 실행 상태로 보낼지 결정합니다.

3️⃣ 실행 (running) : 준비 상태에 있는 프로세스 중 하나가 CPU를 얻어 실제 작업을 수행하는 상태. 실행 상태에 들어간 프로세스는 일정 시간동안 CPU를 사용할 권리를 가집니다. 만약 주어진 시간을 다 사용하고도 작업이 끝나지 않는다면, 프로세스는 준비 상태로 돌아와 (타임아웃) 다음 차례를 기다립니다.

4️⃣ 완료 (terminate) : 프로세스가 작업을 마친 상태. 즉, PCB 블록이 메모리에서 제거된 상태.

 

 

 

그런데 위 4가지 상태만으로도 사실 큰 문제는 없지만, 오늘날 운영체제의 효율성을 고려해서 한 가지 상태가 추가되었습니다. 바로, 대기상태 입니다.

 

5️⃣ 대기 상태 (blocking) : 작업의 효율성을 높이기 위해 입출력을 요청한 프로세스를 실행 상태에 두지 않고 대기 상태로 옮긴 것. 그럼 CPU는 준비 상태에 있는 프로세스 중 하나를 가져다 실행시키겠죠? 나중에 대기 상태의 프로세스는 요청한 입출력이 완료되면 입출력 관리자로부터 인터럽트를 받습니다. 그럼 대기 상태에서 준비상태로 이동하게 되고, 다음 자신의 차례에서 계속 작업을 이어가게 되죠.

 

이 대기 상태까지 그려넣으면 아래와 같은 그림을 그릴 수 있습니다.

 

 

하, 근데 또 여기서 끝난게 아니예요ㅋㅋ 프로세스의 5가지 활성 상태 외에도 특별한 상태가 존재합니다. 휴식 상태와 보류 상태 인데요, 이것도 간단하게 알아볼게요🌝

 

6️⃣ 휴식 상태 (pause) : 프로세스가 일시적으로 작업을 쉬고 있는 상태. 사용하던 데이터가 메모리에 그대로 남아있고, PCB도 유지되므로 프로세스는 멈춘 상태에서 재시작 (resume) 할 수 있습니다.

 

7️⃣ 보류 상태 (suspend) : 프로세스가 메모리에서 잠시 쫓겨난 상태.

  • 메모리가 꽉 차서 일부 프로세스를 메모리 밖으로 보낸 경우
  • 프로그램에 오류가 있어서 실행을 미루어야 하는 경우
  • 바이러스와 같이 악의적인 공격을 하는 프로세스라고 판단될 경우
  • 매우 긴 주기로 반복되는 프로세스라서 메모리 밖으로 쫓아내도 큰 문제가 없는 경우
  • 입출력을 기다리는 프로세스의 입출력이 지연될 경우
  • 등등..

즉, 컴퓨터 성능을 떨어뜨리는 경우나 실행을 미루어도 큰 지장이 없는 경우에 보류 상태가 발생하게 되네요! 휴식상태와 보류 상태의 가장 큰 차이점은 메모리에 남아있냐 아니냐 인데요, 보류 상태의 경우에는 휴식 상태와 달리 메모리 밖으로 쫓겨나 스왑 영역(swap area) 이라는 곳에 보관되어집니다.

여기서 스왑 영역은 메모리에서 쫓겨난 데이터가 임시로 보관되는 곳을 말합니다. 이때 중요한 점은, 저장장치는 스왑 영역에 공간만을 빌려주고 관리는 메모리 관리자(MMU)가 해주게 됩니다! :)

 

 

어후.. 여기까지 작성하는데도 너무 힘이 드네요..... 하지만 제가 공부한건 그래도 다 기록을 해놔야 미래의 제가 편하겠죠..?ㅠㅠㅠㅠ 사실 위 내용에서도 메모리 관리자가 뭐지..? 하는 호기심으로 이어질 수 있지만... 그럼 메모리 영역의 내용까지 모두 다뤄야 하기에ㅋㅋ 일단 프로세스와 관련된 내용으로만 글을 작성할게요ㅠㅠ

 

 

 

그럼 마지막으로 이번엔 프로세스를 복사해보자

네. 프로세스는 생성뿐만 아니라 복사도 할 수 있어요! 복사에 대해서는 fork( )에 대해 알아야 합니다. fork( )실행중인 프로세스로부터 새로운 프로세스를 복사하는 함수로써, 커널에서 제공됩니다. 예를 들면...

  • 워드 프로세서 프로그램으로 문서 작업하다가 새로운 워드프로세서 프로그램을 하나 더 실행시키면, 운영체제는 새로운 워드프로세서 프로그램을 실행하지 않고, fork( ) 시스템 호출을 사용하여 기존의 워드프로세서를 복사합니다. 즉, 처음 워드 프로세서를 실행하는 속도보다 훨씬 빨라요.
  • 크롬에서 Ctrl + N 으로 새로운 크롬 창을 띄울때도 마찬가지입니다.

 

이렇게 기존의 프로세스는 부모 프로세스가 되고, fork로 복사된 새로 생긴 프로세스는 자식 프로세스가 됩니다.

fork의 동작과정을 간단하게 그려보면 아래와 같이 나타낼 수 있어요!

 

fork를 사용하면 아예 처음 프로세스를 생성하는 것보다 속도가 빠르고, 부모-자식 관계가 성립되기 때문에 추가 작업 없이 자원을 상속할 수 있습니다. 그리고 자식이 종료하면 그 정리작업을 부모 프로세스에게 떠넘길 수 있기 때문에, 시스템 관리를 좀 더 효율적으로 할 수 있게 되어요!

 

만약 프로세스가 종료된 후에도 비정상적으로 남아 있는 프로세스가 있다면 그건 미아 프로세스 (좀비 프로세스) 라고 불립니다. 보통 자식보다 부모가 먼저 종료한 경우, 자식은 종료되지 않게 되거나 종료되더라도 자원이 그대로 남아있게 되죠. 그리고 자식이 비정상적으로 종료되어 그 부모가 누군지 몰라 정리할 수 없는 경우도 생깁니다 :(

 

 

 

추가적으로, exec( )라는 것도 있는데요. exec( )는 프로세스를 재활용합니다. 그 프로세스 그대로 사용하는 대신, 내용만 바꾸는 거죠!

 

 

 

 

 


와.. .네.... 드디어 제가 오늘 프로세스에 대해 공부하면서 적어 놓은 내용들을 모두 정리했어요!!!!! 와... 힘들다..........ㅋㅋㅋㅋ 아 근데 생각해보니 메모리의 스택 힙 데이터 코드 영역 같은 프로세스의 구성 쪽이랑 멀티 프로세스 쪽 얘기는 빼먹었네요...... 하ㅜㅜㅜㅜ 너무 많아ㅠㅠㅠ 일단 프로세스는 각각 독립적인 메모리 공간을 할당받아요! 스택, 힙, 데이터, 코드 영역은 각각의 프로세스들이 독립적으로 가지고 있죠! 네!! 그러니까 이건 나중에 멀티 프로세스와 멀티 스레드 다루면서 메모리쪽이랑 함께 얘기할게요... 안그럼 글이 너무 길어짐....😂

 

 

반응형

댓글