결국 컴퓨터란 OS다.
OS가 일종의 주인 역할을 하는 소프트웨어다.
OS가 하는 일 중 가장 중요한 일은 프로그램을 실행시키는 것이다.
프로그램은 결국 실행파일이다.
결국 OS와 실행파일의 합작품을 우리는 컴퓨터가 동작한다고 이야기하는 것이다.
최초의 실행파일은 BIOS이고 BIOS가 부트 로더를 메모리에 올린다.
부트 로더는 OS의 커널을 메모리에 올린다.
부트 로더가 커널을 메모리에 올리면 OS가 실행파일을 실행시킬 수 있는 환경이 마련된 것이다.
실행 파일이 OS에 의해 실행되면 메모리에 올라가 실행된다. 이것을 프로세스라고 한다.
-
프로세스에는 GUI 제공 여부에 따라 포그라운드 프로세스와 백그라운드 프로세스로 나뉜다.
하나의 앱은 기본적으로 하나의 프로세스이지만 Manifest 파일을 잘 바꾸면 두 개 이상의 프로세스에서 실행되도록 바꿀 수도 있다.
또 하나의 프로세스를 여러개의 스레드에서 실행되게 만들 수도 있다.
안드로이드에서 여러 개의 프로세스를 사용할 경우 Binder라는 코드 메커니즘을 통해서 프로세스간 통신을 할 수도 있다.
Binder는 메모리 공유와 데이터 직렬화 등의 작업을 처리할 수 있게 도와준다.
실행 파일의 근본은 결국 명령어 리스트들이다.
실행 파일은 컴퓨터가 실행할 수 있는 명령어들을 포함하는 파일이다.
결국 우리가 하는 일은 컴퓨터가 실행할 수 있는 명령어들을 잘 나열해 놓는 일이라고 볼 수도 있다.
실행 파일이 os에 의해 메모리에 할당된다는 건 실행 파일의 명령어 모음이 메모리에 올라간다는 것이다.
하지만 프로세스라는 건 이것만을 의미하지는 않는다.
실행 파일이 cpu에서 실행되기 위해서 메모리의 다른 3개의 공간을 더 필요로 한다.
첫째로 실행 파일의 전역 변수와 static 변수가 포함되어 있는 data 공간이 필요하다.
둘째로 프로그래머가 코드에 지정해놓은 동적으로 메모리를 활용할 수 있는 공간이 필요하다. heap 영역이라고 부른다.
런타임에 크기를 알 수 있다.
셋째로 지역 변수가 저장되는 stack 공간이 필요하다. 컴파일 타임에 크기가 결정된다.
결국 명령어를 실행하는 주체는 cpu이고 cpu가 명령어를 실행한 결과값은 입출력 장치에 전달된다고 보면 되겠다.
신기한 것은 cpu가 아니라 입출력 장치들이다.
입출력 장치들은 1과 0으로 이루어진 계산 값만 갖고도 여러가지 물리적인 마법을 부릴 수 있다.
결국 cpu가 장치 드라이버의 코드를 실행시킨 값들이 하드웨어에 전달된다.
드라이버는 중간 계층 소프트웨어다.
결국 cpu가 입출력장치와 직접적으로 소통한다는 점은 변하지 않는다.
다만 드라이버라는 중간 계층 소프트웨어가 기기마다 다른 프로토콜을 적용하여 일종의 추상화를 제공한다고 이해할 수 있다.
-
Code 영역, CPU, PC register 이 3개의 공통점은 이 3개가 협력하여 명령어들이 실행된다는 것이다.
PC register는 CPU 내부에 있다.
-
동시성은 사실 구라다. 동시에 실행되지 않지만 동시에 실행되는 것처럼 느낄 정도로 빨라서 동시성이라고 부른다.
하나의 cpu는 한 번에 하나의 프로세스만 실행시킬 수 있다.
프로세스를 엄청나게 빠르게 번갈아가면서 실행시키면 동시에 실행되는 것처럼 보이는 데 이를 동시성이라고 한다.
병렬성은 정말 동시에 실행되는 개념이다.
코어가 여러개 있기 때문에 정말 여러개의 프로세스가 동시에 실행될 수 있다.
-
멀티 코어 프로세스라는 건 이렇게 동작한다.
먼저 컴퓨터 전원을 킨다.
그러면 ROM에 저장된 BIOS라는 프로그램이 동작하기 시작한다.
이 BIOS라는 저장 장치에서 부트 로더를 찾아 메모리로 옮긴다.
부트 로더가 cpu의 첫 번째 코어에서 동작한다.
이후에 운영체제를 불러오게 되는데, 운영체제는 여러 개의 코어에 나누어서 실행된다.
그런데 여기서 의문점을 하나 가져야 한다.
운영체제는 하나의 프로그램이고 하나의 프로세스인데 어떻게 서로 다른 cpu에서 실행될 수 있는가?
여기서 스레드라는 개념이 중요하게 작용한다.
운영체제 자체가 여러개의 스레드로 나뉘어져 있어서 이게 가능한 것이다.
예를 들어 커널의 스케쥴러 스레드는 코어1에서, 파일 시스템을 관리하는 스레드는 코어2에서 실행될 수 있다.
-
스레드의 가장 중요한 부분은 메모리 영역을 공유할 수 있다는 것이다.
다시 말하면 하나의 프로그램이 앞서 말했듯이 4개의 공간으로 나뉘어진 메모리 공간을 공유하는게 아니라는 뜻이다.
스레드란 결국 코드 영역을 하나의 명령어 집합이라고 볼 때 그 집합의 부분 집합이라고 볼 수 있다.
이러한 구분은 개발자가 명시적으로 설정해야 한다.
다만 운영체제가 실행 순서를 관리할 뿐이다.
스레드 관점에서 하나의 프로세스는 이렇게 표현된다.
PC와 SP 모두 레지스터에 값이 저장되고 복원되는 방식으로 진행된다.
하나의 cpu는 하나의 pc와 하나의 sp를 가질 뿐이다.
결국 멀티 스레드 환경이라는 것은 메모리를 공유하지만, 다른 프로세스처럼 cpu에서 동작한다.
이는 운영체제와 개발자가 협력한 결과다.
운영체제라는 프로그램 자체도 하나의 메모리 공간을 할당받아 여러개의 스레드로 나뉘어서 별도의 cpu 코어에서 실행된다.
운영체제의 heap 영역에서 동적 메모리 할당을 위한 기능들을 수행한다.
프로세스들이 서로의 메모리 공간을 침범하지 않도록 하는 기능을 heap 영역을 통해 구현하는 것이다.
운영체제에 해당하는 메모리 공간에 PCB가 저장된다.
결국에 운영체제가 프로세스를 관리하니까 당연한 일이다.
context switching즉 운영체제가 프로세스를 번갈아가면서 실행시킬 때마다 pcb가 저장되었다가 삭제되었다가 하는 것이다.
-
멀티 프로세스는 메모리를 구분하는 것이고 멀티 스레드는 cpu를 구분하는 것이다.
안정성을 주려면 멀티 프로세스를 사용해 메모리를 구분하여 사용하는 것이 옳고,
효율성을 추구하려면 cpu를 최대한 활용해 멀티 스레드를 활용하는 것이 좋다.
-
운영체제라는 프로그램에 대해서 생각해 볼 때,
프로세스간에 데이터 공유와 스레드간의 데이터 공유에 대해 알아보아야 한다.
멀티 스레드는 그냥 말 그대로 같은 메모리 공간을 참조할 수 있다.
멀티 스레드라는 말 자체가 그냥 같은 메모리 공간에 있는 코드들이 서로 다른 cpu에서 실행된다는 말이기 때문.
저장되기 전에 그 값의 이전 값을 다른 스레드에서 사용해버리면 연산 결과가 달라진다.
이를 경쟁 상황이라고 한다.
결국 이런 스레드의 자원 공유 문제는 운영체제라는 프로그램 내에서 소프트웨어적으로 해결해야 한다.
mutex, semaphore가 대표적인 알고리즘이다.
멀티 프로세스 환경에서는 IPC를 통해 메모리 공간을 공유할 수 있다.
메모리 공간을 운영체제가 대여해주는 느낌.
운영체제의 직접적인 허락 없이 그냥 메모리 공간을 사용할 수 있다.
이렇게 될 경우 멀티 스레드 환경과 다른 것이 없다.
운영체제 없이 자체적으로 소프트웨어적으로 동기화 문제를 해결해야 한다.
두 번째 방식은 메시지 전달이라는 운영체제 고유의 기능을 활용하는 것이다.
운영체제가 데이터를 받고 데이터를 전달해주는 것이다. 시간이 오래 걸리는 단점이 있다 당연히.
하지만 프로세스간 통신은 필수이기 때문에 운영체제를 거치든, 거치지 않든 꼭 해야하는 과정이다.
-
데드락은 멀티 스레드 환경에서의 문제점이다.
-
멀티 스레드 환경을 해결하는 여러가지 방법론들이 필요하다.
'Computer' 카테고리의 다른 글
[ Tebah ] Tebah 앱 개발기 : 도메인 설계를 시작하며 (1) | 2025.04.19 |
---|---|
[Android] JVM vs ART (0) | 2025.03.22 |
[Android] Kapt Error (2) | 2024.12.10 |
[Kotlin] 클래스를 상속받을 때 주의할 점 (0) | 2024.12.09 |
[Jetpack Compose] Compose, 최적화를 위한 원칙 (0) | 2024.11.21 |