[OS] Process

jkeum·2022년 11월 27일
1

OS

목록 보기
1/1

Process

컴퓨터가 처음 나왔을 때는 컴퓨터가 있으면 작업이 하나가 들어와서 처리되고, 그 작업이 끝나고 나면 또 그 다음 작업이 들어와서 처리되는 방식이었다.
작업이 입출력 등의 일을 하는 중에는 CPU가 놀고 있게 되어서 낭비가 있었다.
이를 해결하고자 메모리에 여러 프로그램을 올려두고 그걸 동시에 실행시키려고 하니, CPU가 하나라서 불가능했다.
하지만 Time Sharing(시분할) 방식을 쓰면 여러 작업을 동시에 실행시킬 수 있다.
실제로는 CPU에서 프로세스를 동시에 실행시키는 게 아니지만, 시간 단위가 ns로 굉장히 짧아서 time sharing 방식을 사용하면 동시에 실행하는 것처럼 보인다.

The Process

프로세스는 실행 중인 프로그램을 의미하며, 하나의 독립된 실행단위이다.
프로세스의 활동 상태를 program counter(PC)와 프로세서의 register의 내용으로 표시한다.
PC는 프로그램이 실행되고 있는 code 영역을 가리키고 있으며, instruction을 가지고 온다.
그 프로세스를 가져올 때 사용되는 register가 현재 상태값을 가지고 있다.
프로세스의 메모리는 다음과 같은 섹션으로 나뉜다.

  • Text(Code) - 실행 코드가 저장되는 영역
  • Data - 전역 변수, static 변수가 저장되는 영역
  • Heap - 프로그램이 실행되는 중에 동적으로 할당되는 메모리가 저장되는 영역
  • Stack - 함수를 호출할 때 임시로 데이터가 저장되는 영역(함수 파라미터, 리턴 주소, 지역변수 등)

Text와 Data 영역은 크기가 고정되어 프로그램이 실행되는 동안 그 크기가 변하지 않는다.
하지만 Stack과 Heap 영역은 프로그램 실행 동안 크기가 줄어들거나 늘어날 수 있다.
함수가 호출되면 activate 되었다고 하는데, 그 함수가 사용하는 변수에 대한 공간(함수가 active 상태일 때 사용하는 공간)을 activation record라고 한다.
여기에는 함수 파라미터, 지역 변수, 리턴 주소 등이 포함되며 Stack에 push된다.
함수가 끝나게 되면 그 activation record도 Stack에서 pop되어 나온다.
Heap도 메모리가 동적으로 할당되면 그 크기가 늘어나고, 메모리가 시스템에 반환되면 다시 줄어들 것이다.

Process State

프로세스가 실행되면 그 상태가 변경된다.
상태는 해당 프로세스의 현재 활동에 의해 정의된다.

  • New - 프로세스가 생성됨.
  • Running - 명령이 실행되고 있음.
  • Waiting - 프로세스가 어떤 이벤트가 발생하길 기다리고 있음(I/O 완료 또는 signal 수신).
  • Ready - 프로세스가 프로세서에 할당되기를 기다리고 있음.
  • Terminated - 프로세스의 실행이 끝남.

프로세스가 처음에 생성이 되면 New.
fork() system call로 새로 생성이 되면, Ready 상태가 된다.
프로세스가 하나라면 바로 실행되겠지만, 멀티프로그래밍으로 인해 여러 개의 프로세스가 메모리에 있으면 그 중 하나에 CPU를 할당해준다.
이 일은 scheduler가 하며, 어떤 프로세스를 먼저 실행시킬지 선택한다.
선택이 되면 Run 상태로 간다.
A, B, C, D 프로세스가 있을 때 이 프로세스들을 동시에 실행시킬 수 없으므로 시분할 방법으로 실행시킨다.
그러다가 작업이 끝나면 Terminate(exit) 상태가 된다.
운영체제에서 시분할 방식을 사용할 때, 프로세스마다 CPU를 사용할 수 있는 시간(time quantum)을 지정해준다.
그 시간 안에 작업이 끝나면 문제가 없지만, 그 안에 작업이 끝나지 않으면 timeout에 걸린다.
그 프로세스에 할당된 시간을 다 썼으므로 다른 프로세스에게 CPU를 넘기게 되며, 이때 Run에서 Ready로 다시 돌아온다.
이런 상황을 preemptive(선점)라고 하며, 자원을 사용하던 사람이 반납하기 전에 강제로 그 자원을 뺏어오는 것을 의미한다.
Wait에는 크게 두 종류가 있다.
하나는 자의적으로 할 일이 없어서 혹은 실행할 여건이 안 되어서 대기하고 있는 경우이다.
또 다른 하나는 동기화 문제로, 예를 들어 내가 프린터를 사용하고 싶은데 다른 누군가 이미 사용 중이라면 그 사람이 사용을 끝낼 때까지 대기해야 한다.
Wait 상태로 들어왔던 프로세스는 언젠가는 Ready 상태로 가야 한다.

Process Control Block(PCB)

각 프로세스는 Process Control Block(PCB)으로 운영체제에 나타난다.
여기에는 다음과 같이 특정 프로세스와 관련된 정보들이 포함된다.

  • Process state - 상태는 New, Ready, Running, Waiting, Halted 등이 될 수 있음.
  • Program counter - PC는 프로세스가 실행할 다음 명령의 주소를 나타냄.(프로세스가 다른 작업을 하다가 돌아왔을 때 이전에 멈췄던 상태에서의 PC값. 거기서부터 다시 시작해야 함.)
  • CPU registers - 레지스터는 컴퓨터 아키텍처에 따라 그 수와 타입이 다름. PC와 함께 이 상태 정보는 인터럽트가 발생할 때 저장되어야 나중에 실행이 다시 스케줄링 될 때 프로세스가 올바르게 지속될 수 있음.(프로세스 A가 실행될 때, CPU의 register 값들은 A를 위한 register임. 프로세스 A가 사용하고 있었으므로 어떤 값이 있었을텐데, 만약 프로세스 B로 넘어가게 되면 그때 프로세스 A가 사용하던 register 값들을 해당 PCB에 저장해두고 프로세스 B의 상태로 바꿈.)
  • CPU-scheduling information - 프로세스 우선 순위, 스케줄링 대기열에 대한 포인터 및 기타 스케줄링 매개변수가 포함됨.
  • Memory-management information - 운영체제에서 사용하는 메모리 시스템에 따라 base및 limit register와 page table, segment table의 값이 포함될 수 있음.
  • Accounting information - 사용된 CPU 및 사용된 실제 시간, 제한 시간, account 번호, 작업 또는 프로세스 번호 등이 포함됨.
  • I/O status information - 프로세스에 할당된 I/O 디바이스 목록, 오픈된 파일 목록 등이 포함됨.

운영체제에서는 프로세스가 하나 만들어지면 그 프로세스를 위한 PCB를 하나 만들어서 프로세스에 대한 모든 정보를 넣고, 프로세스가 종료되면 PCB도 사라진다.

Process Scheduling

CPU 사용률을 최대화하기 위해 멀티프로그래밍을 사용하며, 이는 일부 프로세스가 항상 실행되도록 한다.
CPU가 작업을 계속 해야 그 컴퓨터 시스템의 throughput(단위 시간 당 처리량)이 올라간다.

프로세스 수가 많아질수록 throughput이 올라가다가 어느 한계에 도달하면 overload가 발생해서 성능이 확 떨어진다.
시분할 방식은 프로세스 간 CPU 코어를 자주 전환하여 사용자가 각 프로그램이 실행되는 동안 상호작용을 할 수 있도록 한다.
이를 위해 프로세스 스케줄러는 코어에서 프로그램을 실행하기 위해 사용 가능한 프로세스를 선택한다.
각 CPU 코어는 한 번에 하나의 프로세스를 실행할 수 있다.

Scheduling Queues

프로세스가 시스템에 진입하면, CPU 코어에서 실행될 준비가 되어 ready queue에 들어간다.
이 대기열은 일반적으로 linked list로 저장된다.
Ready queue의 헤더에는 리스트의 첫 번째 PCB에 대한 포인터가 포함되어 있으며, 각 PCB에는 ready queue의 다음 PCB를 가리키는 포인터 필드가 포함되어 있다.

프로세스에 CPU 코어가 할당되면, 잠시 실행되다가 종료가 되거나(terminate), 중단이 되거나(interrupt), 혹은 I/O 요청 완료와 같은 특정 이벤트가 발생하기를 기다린다.
프로세스가 디스크 같은 장치에 I/O 요청을 한다고 가정한다.
장치는 프로세서보다 훨씬 느리게 실행되기 때문에 프로세스는 I/O를 사용할 수 있을 때까지 기다려야 한다.
이렇게 특정 이벤트가 발생하기를 기다리는 프로세스는 wait queue에 들어간다.
대기를 하게 되는 이유에 따라 wait queue가 여러 개 생성된다.

새로운 프로세스는 처음에 ready queue에 들어간다.
실행되기 위해 선택되거나 dispatch될 때까지 대기한다.(선택된 프로세스가 실제로 동작할 수 있도록 작업해주는 것을 dispatch라고 하며, 그 프로그램을 dispatcher라고 함.)

프로세스가 I/O 요청을 한 다음에 I/O wait queue에 들어갈 수 있다.
프로세스에서 파일을 읽어달라고 요청을 한다면, 운영체제에서는 파일을 읽는 명령을 보내고 프로세스는 그 파일이 다 읽힐 때까지 할 일이 없으므로 대기한다.

새로운 자식 프로세스를 생성한 다음 자식 프로세스가 종료되기를 기다리는 동안 wait queue에 들어갈 수 있다.
자식 프로세스가 종료되면 다시 ready queue로 들어간다.

프로세스가 interrupt 또는 time slice 만료로 인해 강제로 코어에서 제거되어 다시 ready queue에 들어갈 수 있다.

프로세스는 종료될 때까지 이런 주기를 계속하며, 종료가 되면 모든 대기열에서 제거되고 PCB와 자원이 할당 해제된다.

Context Switch

프로세스 A, B, C, D가 있다고 가정한다.
프로세스 A가 돌다가 timeout이 걸리면 운영체제 쪽으로 컨트롤이 넘어간다.
프로세스 A가 스케줄링 되었을 때, A의 PCB에서 한 부분에는 이 프로세스가 사용할 수 있는, 할당된 시간을 적어둔다.
예를 들어 이 time slice가 10ms라고 가정한다.
Timer interrupt 걸리는 것을 tick이라고 하는데, 운영체제에서 사용하는 기본적인 시간 단위이다.
Timer interrupt를 1ms 걸어놨다고 하면, A는 10개의 tick을 사용할 수 있다.
실행되는 동안 1ms마다 timer interrupt가 걸리고, 그럼 10개의 tick에서 하나씩 값을 빼주면 된다.
그러다가 그 값이 0이 되면 할당된 시간이 다 되었다는 것이므로 운영체제에서 preempt를 해야겠다고 판단한다.
Preempt를 해서 프로세스 A의 현재 상태(PCB에 있는 PC값)를 PCB에 저장해야 한다.(state save)
그 다음에 운영체제는 스케줄러를 이용해 다른 프로세스 B, C, D 중 하나를 선택한다.
만약 스케줄러가 프로세스 B를 선택했다면, dispatcher가 B를 실행하게 해준다.
그러려면 프로세스 B의 PCB에서 이전에 저장해놨던 상태들을 register로 옮겨야 한다.(state restore)
그 다음에 프로세스 B가 실행된다.

이렇게 인터럽트는 운영체제가 현재 작업에서 CPU 코어를 변경하고 커널을 실행하게 한다.
인터럽트가 발생하면, 시스템은 CPU 코어에서 실행 중이던 프로세스의 현재 context를 저장한다.
그렇게 해야 인터럽트 처리가 완료되고 나서 그 context를 복원할 수 있기 때문이다.
CPU 코어를 다른 프로세스로 전환하기 위해 현재 프로세스의 상태를 저장하고 다른 프로세스의 상태를 복원하는 작업을 context switch라고 한다.
Context switch 시간은 시스템이 전환되는 동안 유용한 작업을 수행하지 않기 때문에 overhead이다.
Timeout이 짧을수록 context switch가 빈번하게 일어나는데, 이때 드는 비용이 적지 않다.
따라서 timeout을 짧게 하면 context switching overhead가 커진다는 단점이 있다.

profile
It's me, jkeum!

1개의 댓글

comment-user-thumbnail
2022년 11월 27일

운영체제의 프로세스 관리 방법에 대해 자세하게 작성해 주셔서 많이 배워갑니다!

답글 달기