개발_기록용

[컴퓨터 밑바닥의 비밀 내용정리] 2.1 운영체제, 프로세스, 스레드의 근본 본문

Computer Science

[컴퓨터 밑바닥의 비밀 내용정리] 2.1 운영체제, 프로세스, 스레드의 근본

나폴나폴 2025. 2. 22. 16:24
728x90

0. 들어가며


  • 굉장히 감명깊게 읽었던 [컴퓨터 밑바닥의 비밀] 책의 내용을 돌아보기 위해 정리글을 작성한다.
  • 전공자로 어느정도 안다고 생각한 내용들에서도 부족한 부분이 보여 책을 다시 읽어보며 정리하고자 한다.

https://link.coupang.com/a/cdaqFv

 

컴퓨터 밑바닥의 비밀:컴퓨터 시스템의 본질을 알면 코드의 실마리가 보인다 - 보안과 해킹 | 쿠

쿠팡에서 4.3 구매하고 더 많은 혜택을 받으세요! 지금 할인중인 다른 3 제품도 바로 쿠팡에서 확인할 수 있습니다.

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."

(본문 소개 링크로 도서 구입 시 일정액의 수수료를 제공받습니다.)


1. 주제

CPU는 프로세스, OS, 스레드 같은 개념을 모른다.

단지 다음 2가지 사항만 알고 있다.

  1. 메모리에서 명령을 하나 가져온다. (인출)
  2. 이 명령어를 실행하고, 다시 1번으로 돌아간다.

CPU가 명령어를 메모리에서 가져올 수 있는 것은 프로그램카운터(PC)에

다음에 실행될 명령어의 메모리 주소를 알기에 가능하다.

 

우선, PC 레지스터가 저장하는 주소는 기본적으로 1씩 증가한다.

  대부분 CPU가 주소를 하나씩 증가시키며 차례대로 명령어를 실행하기 때문이며

if else나 함수 호출같은 명령어를 만나면 이런 순차적인 실행 순서가 파괴되니

CPU는 연산 결과나 명령어에서 지정한 점프할 대상 주소에 따라 PC 레지스터 값을 동적으로 변경한다.


Q) 그럼 최초의 PC 레지스터 값은 어떻게 지정되는가?

 

 → 프로그램이 시작되면 main함수에 대응하는 첫번째 기계 명령어의 주소를 찾아

이를 PC 레지스터에 기록한다.

그러면 우리가 위의 과정으로 CPU에게 프로그램을 실행하게 하면

운영체제 없이도 실행이 가능하지만..

  • 프로그램을 적재할 수 있는 적절한 크기의 메모리 영역 찾기
  • CPU 레지스터를 초기화하고, 함수의 진입포인트(entry point)를 찾아 PC 레지스터를 설정한다.

수동으로 위의 두 작업을 해줘야 한다.

 

거기에 멀티태스킹이 불가하고(여러 프로그램을 동시에 사용하는게 사실상 불가능),

라이브러리 사용도 안되며, 사용할 하드웨어와 드라이버 직접 연결 등 매우 불편하다.

(실제로 50~60년대까지 이렇게 수동으로 관리했다고 한다.)


2. 멀티 태스킹 지원을 위한 '프로세스'의 탄생

프로그램 여러개를 매우 빠른 속도로 서로 전환하고, 전환 시 이전에

CPU가 수행하던 상태 정보를 저장하면 되는데, 이 상태 정보가 context이다.

 

실행중인 모든 프로그램은 context를 포함한 여러 정보를 저장할 수 있는 형태의

구조체를 가져야하는데, 이를 프로세스라 한다.

 

이제 우리는 디스크에서 메모리에 프로그램을 자동으로 적재해주는 적재도구(loader)와,

멀티태스킹을 실현해주는 프로세스 관리 도구 등을 써야 한다.

 

이런 여러 도구와 기능들을 지원해주는걸 '운영체제'라 한다.

(운영체제만 있으면 수동으로 50~60년대처럼 관리할 필요가 없다.)

 

아래 그림을 살펴보자. 메모리에 프로그램이 적재된 상태를 나타냈다.

 

코드 영역의 funcA와 funcB는 직렬 프로그래밍과 다중 프로세스 프로그래밍으로 처리가 가능하다.

 

  • 직렬프로그래밍은 funcA가 끝나야 funcB가 실행되니, 두 함수가 서로 무관함에도 기다려야해서 비효율적
  • 다중프로세스 프로그래밍은 프로세스 A, B를 생성하여 각각 funcA, funcB의 결과를 얻고 B의 결과를 A에 전달해 처리. 근데 전달하는 과정에서 통신 문제 가능성, 프로세스 생성시 오버헤드가 크며, 프로세스마다 서로다른 자체적인 주소 공간을 가져 프로세스간의 통신을 해야하고, 이는 복잡한 과정이다.

위의 두 방법을 살펴보니 모두 부담이 되는데, 더 좋은 방법이 없을까 하고 나온게 스레드이다.

 

3. 프로세스에서 스레드로 진화

CPU가 실행하는 기계명령어와 함수가 실행되면 프로세스 주소 공간의 스택 영역에 이 정보들이 저장된다.

→ 이때, 진입 함수가 main 함수 하나뿐이라 프로세스의 기계 명령어는

한번에 하나의 CPU만 실행할 수 있다.

= 이는 곧, '하나의 프로세스에는 하나의 실행 흐름만 존재' 한다는 뜻이다.

 

그러면.. PC 레지스터가 main 함수를 가리키게 할 수 있듯이

PC 레지스터가 다른 함수를 가리킬 수 있다면 새로운 실행 흐름이 되는 것일까?

 

→ 그리고 이 방법은, 동일한 프로세스 주소 공간을 공유하므로 통신도 필요하지 않다.


 

이처럼 각 CPU의 PC 레지스터가 실행할 진입함수를 서로 다르게 설정할 수 있고,

이러면 하나의 프로세스 안에 여러 개의 실행 흐름이 존재하게 되며, 이 실행 흐름을 스레드라 한다.

 

CPU의 PC레지스터에 스레드의 진입함수 주소를 지정하면 스레드를 실행할 수 있다.

 스레드를 생성할 때 진입함수를 반드시 지정해야 하는 이유!


 

스레드는 결국 서로다른 주소 공간의 프로세스에 존재하는 것이 아닌

동일한 프로세스 내에 존재하므로 근본적으로 통신이라는 개념도 없고 불필요하다

 

또한, 다중코어가 있어야만 멀티 스레드를 쓸 수 있는 것은 아니다.

 

스레드는 운영체제 계층에서 구현되며 코어 개수와 무관해서

단일 코어에서도 스레드를 여러개 생성할 수 있고

CPU가 기계 명령어를 실행할 때도 실행중인 기계 명령어가 어떤 스레드에 속해 있는지 알지 못한다.

 

스레드에는 다중 코어를 충분히 활용하는 것 외에 또다른 용도가 있다.
예를 들어, 그래픽 사용자 인터페이스 프로그래밍을 할 때
특정 이벤트(event)를 처리하는데 많은 시간이 필요해 응답이 없는 상황을 방지하고자
해당 이벤트를 처리하는 별도의 스레드를 생성할 수 있다.

 

물론 스레드는 우리가 잘 알고 있듯이 상호 배제(mutual exclusion)와 동기화 문제가 있어서

이 문제를 해결해야 한다.

 

반응형
Comments