개발자가 알아야 할 배경지식에 초점을 맞춘 CPU
: CPU 안에 있는 작은 임시 저장장치
CPU 안에는 다양한 레지스터들이 있고, 각기 다른 이름과 역할이 있음
프로그램을 이루는 데이터와 명령어가 프로그램의 실행 전후로 레지스터에 저장되기 때문에 레지스터에 저장된 값만 잘 관찰해도 비교적 낮은 수준의 프로그램이 어떻게 작동하는지를 파악할 수 있음
> WinDbg(윈도우), gdb(리눅스/맥) 등 디버깅 도구를 이용해 관찰할 수 있음
1️⃣ 프로그램 카운터(Program Counter, PC): 메모리에서 다음으로 읽어 들일 명령어의 주소를 저장하는 레지스터
> "명령어 포인터"라고 부르는 CPU도 있음
- 프로그램 카운터는 CPU가 다음에 실행할 명령어의 위치를 기억하는 역할을 함
- 보통은 1씩 증가하지만, 조건문, 반복문, 리턴문 같은 코드가 실행되면 특정 위치로 점프할 수도 있음
2️⃣ 명령어 레지스터(Instruction Register, IR): 해석할 명령어, 즉 메모리에서 방금 읽어 들인 명령어를 저장하는 레지스터
- 명령어 레지스터는 CPU가 방금 가져온 명령어를 저장하는 공간
- CPU는 이 명령어를 해석해서 "어떤 연산을 할지", "어떤 장치를 움직일지" 결정
3️⃣ 범용 레지스터(General Purpose Register, GPR): 다양하고 일반적인 상황에서 자유롭게 사용할 수 있는 레지스터
- 범용 레지스터는 "아무데나" 쓸 수 있는 빠른 저장 공간
- 메모리보다 훨씬 빠르게 접근 가능해서 CPU 연산 속도를 높이는 데 도움 됨
4️⃣ 플래그 레지스터(Flag Register): 연산의 결과 혹은 CPU 상태에 대한 부가 정보인 플래그 값을 저장하는 레지스터

- 플래그 레지스터는 "CPU 연산 결과가 어떤 상태인지"를 기록하는 공간
- 연산 결과가 음수인지(부호 플래그), 0인지(제로 플래그), 자리올림이 있는지(캐리 플래그) 등을 저장
- CPU는 이 플래그 값을 참고해서 다음 동작을 결정
5️⃣ 스택 포인터(Stack Pointer, SP): 메모리 내 스택 영역의 최상단 스택 데이터 위치를 가리키는 특별한 레지스터
- 스택 포인터는 "스택의 가장 위에 있는 데이터의 위치"를 기억하는 레지스터
- 스택에 데이터를 넣으면(푸시) SP가 증가, 데이터를 꺼내면(팝) SP가 감소
- CPU는 이 스택을 이용해서 함수 호출, 변수 저장 등을 처리

이 레지스터들이 협력하면서 CPU가 프로그램을 실행
: CPU의 작업을 방해하는 신호
(Interrupt: "방해하다", "중단시키다")
인터럽트는 다양한 상황에서 발생할 수 있음
임의로 발생시킬 수도 있고, 잘못된 프로그램으로 인해 발생하기도 하며, 효율적인 입출력을 위해 사용되기도 함
> 사용자가 직접 발생 (예: 키보드 입력, 마우스 클릭)
> 잘못된 프로그램 실행 (예: 0으로 나누는 오류)
> 입출력 장치의 요청 (예: 프린터 완료, 하드디스크 데이터 요청)
동기 인터럽트(= 예외)
- CPU 자체에서 발생하는 인터럽트
- 예시: 0으로 나누기, 접근 불가능한 메모리 접근 등
비동기 인터럽트(= 하드웨어 인터럽트)
- 주로 입출력 장치에서 발생하는 인터럽트, 특정 시간이 아닌, 언제든지 발생할 수 있음
- 예시: 키보드 입력, 네트워크 데이터 수신 등
> 비동기 인터럽트를 일반적으로 "인터럽트"라고도 하지만, 용어 혼동을 방지하기 위해 "하드웨어 인터럽트"라고 부르기도 함
- 인터럽트는 CPU가 실행 중인 작업을 잠시 멈추고 더 중요한 요청을 처리하는 신호
- 동기 인터럽트 → CPU가 오류(예외)로 인해 발생시키는 인터럽트
- 비동기 인터럽트 → 키보드, 마우스, 네트워크 등 외부 장치가 보내는 신호
- CPU는 인터럽트 요청을 처리한 뒤 원래 작업으로 복귀함
작업 완료 여부를 계속해서 확인하는 것은 인터럽트와 대비되는 폴링 이라는 기법
→ 입출력 작업에서 폴링이란 입출력장치의 상태가 어떤지, 처리할 데이터가 있는지 주기적으로 확인하는것을 말함
CPU는 효율적으로 명령어를 처리하기 위해 하드웨어 인터럽트를 사용
입출력 완료 여부를 확인하기 위한 CPU 사이클 낭비를 최소화하고, CPU가 다른 일을 수행할 수 있는 시간을 벌어 줌으로써 효율적으로 명령어를 처리할 수 있도록 도움
1️⃣ "인터럽트 요청 신호"를 CPU에 전달
2️⃣ CPU는 실행 사이클이 끝나고 명령어를 인출하기 전에 항상 인터럽트 여부 확인
3️⃣ CPU는 인터럽트 요청을 확인하고, "인터럽트 플래그"를 통해 현재 인터럽트를 받아들일 수 있는지 여부 확인
4️⃣ 인터럽트를 받아들일 수 있다면 CPU가 지금까지의 작업을 백업
5️⃣ CPU는 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴을 실행
6️⃣ 인터럽트 서비스 루틴 실행이 끝나면 4️⃣에서 백업해 둔 작업을 복구하여 실행을 재개
인터럽트는 CPU의 정상적인 실행 흐름을 끊는 것이기 때문에 인터럽트하기 전에 CPU에게 인터럽트의 가능 여부를 확인해야함 이를 위한 신호를 인터럽트 요청 신호라고 함
이때 CPU가 인터럽트 요청을 수용하기 위해서는 플래그 레지스터의 인터럽트 플래그가 활성화되어 있어야 함
만약 인터럽트 플래그가 불가능으로 설정되어 있다면 CPU는 인터럽트 요청이 오더라도 해당 요청을 무시
다만, 모든 하드웨어 인터럽트를 인터럽트 플래그로 막을 수 있는 것은 아님
인터럽트 플래그가 불가능으로 설정되어 있더라도 무시할 수 없는 인터럽트 요청도 있음
무시할 수 없는 하드웨어 인터럽트는 가장 우선순위가 높은, 다시 말해 가장 먼저 처리해야 하는 인터럽트를 말함
정전이나 하드웨어 고장으로 인한 인터럽트가 이에 해당. 즉, 하드웨어 인터럽트에는 인터럽트 플래그로 막을 수 있는 인터럽트와 막을 수 없는 인터럽트가 있음
CPU가 인터럽트 요청을 받아들이기로 했다면 CPU는 인터럽트 서비스 루틴이라는 프로그램을 실행
CPU가 인터럽트를 처리한다는 말은 인터럽트 서비스 루틴을 실행하고, 본래 수행하던 작업으로 다시 되돌아온다는 말과 같음
- 하드웨어 인터럽트: CPU가 요청을 받아 입출력장치의 작업을 처리하고 다시 원래 작업으로 돌아가는 과정
- 효율적 처리를 위해 CPU가 사용하는 중요한 메커니즘
📌 CPU가 인터럽트를 처리하는 과정
1️⃣ 하드웨어 장치가 인터럽트 요청 신호를 CPU에 전달
2️⃣ CPU는 실행 중인 명령어를 완료한 뒤, 인터럽트 여부를 확인
3️⃣ 인터럽트 플래그를 확인해 요청을 수락할지 결정
4️⃣ 요청 수락 시, 현재 작업(프로그램 카운터와 레지스터 값)을 스택에 백업
5️⃣ 인터럽트 벡터를 통해 ISR(인터럽트 서비스 루틴) 실행
6️⃣ ISR 처리 완료 후 스택에서 작업을 복구하고 원래 실행하던 작업을 재개한 줄 정리
- CPU가 인터럽트를 처리한다는 것은 인터럽트 서비스 루틴을 실행하고, 백업된 작업 상태를 복구한 뒤 원래 작업으로 복귀하는 것
예외가 발생한 명령어부터 실행하느냐, 예외가 발생한 명령어의 다음 명령어부터 실행하느냐에 따라 폴트와 트
랩으로 나뉨
클럭
: 컴퓨터의 부품을 일사불란하게 움직일 수 있게 하는 시간의 단위
클럭 속도는 헤르츠(Hz) 단위로 측정하며, 최근에는 기가헤르츠(GHz) 단위로 측정하는 것이 일반적

클럭 속도가 높아지면 CPU는 명령어 사이클을 더 빠르게 반복하고, 다른 부품들도 그에 맞춰 더 빠르게 작동할 것으로 기대할 수 있음
실제로 클럭 속도가 높은 CPU는 일반적으로 성능이 더 뛰어남
이런 점에서 클럭 속도는 CPU의 속도 단위로 간주되기도 함
하지만 클럭 속도를 필요 이상으로 높이면 발열 문제가 발생할 수 있어, 단순히 클럭 속도를 높이는 것만으로 CPU 성능을 향상시키는 데에는 한계가 있음
클럭 속도를 높이는 방법 외에도, 코어 수나 스레드 수를 늘리는 방식으로 CPU의 성능을 높일 수 있음

하드웨어 스레드와 소프트웨어 스레드의 차이는 동시성과 병렬성이라는 개념으로 더 명확히 이해 가능
병렬성:
- 작업을 물리적으로 동시에 처리하는 성질
예: 4개의 하드웨어 스레드가 각각 4개의 명령어를 동시에 실행
동시성:
- 작업이 동시에 실행되는 것처럼 보이는 성질
- 실제로는 CPU가 빠르게 작업을 번갈아 처리하여 사용자가 동시 실행으로 인식
한 줄 요약
- 병렬성: 실제로 여러 작업이 동시에 실행됨(하드웨어 스레드)
- 동시성: 동시에 실행되는 것처럼 보이는 효과(소프트웨어 스레드)
- 하드웨어 스레드는 병렬성을, 소프트웨어 스레드는 동시성을 구현
- 1코어 1스레드 CPU에서도 여러 소프트웨어 스레드를 실행할 수 있음
- 실제로는 하나의 CPU가 스레드 간 빠르게 전환하며 실행
- 하드웨어 스레드는 물리적 실행 단위, 소프트웨어 스레드는 운영체제가 관리하는 논리적 실행 단위임
명령어 병렬 처리 기법
: 여러 명령어를 동시에 처리하여 CPU를 한시도 쉬지 않고 작동시킴으로써 CPU의 성능을 높이는 기법
기억해야할 명령어 처리 기법인 명령어 파이프라이닝을 이해하려면 우선 하나의 명령어가 처리되는 과정을 비슷한 시간 간격으로 나누어 보아야 함. 일반적으로 아래와 같음
이처럼 공장의 생산 라인과 같이 명령어들을 명령어 파이프라인에 넣고 동시에 처리하는 기법을 명령어 파이프라이닝 이라고 함
> 슈퍼스칼라
: 현대 대부분의 CPU는 여러 개의 파이프라인을 이용하는데 이처럼 CPU 내부에 여러 명령어 파이프라인을 포함하는 구조
슈퍼스칼라 구조로 명령어 처리가 가능한 CPU는 슈퍼스칼라 프로세서 혹은 슈퍼스칼라 CPU라고 부름

한 줄 요약
- 파이프라이닝은 명령어 병렬 처리를 통해 CPU를 쉬지 않고 작동시켜 성능을 높이는 기술
- CISC는 명령어 복잡성으로 인해 파이프라이닝에 비효율적, RISC는 규격화된 명령어로 최적화되어 있음
: 파이프라이닝이 제대로 작동하지 않아 CPU 성능이 저하되는 상황
1️⃣ 데이터 위험: 명령어 간의 데이터 의존성으로 인해 발생
2️⃣ 제어 위험: 프로그램 카운터의 갑작스러운 변화에 의해 발생
3️⃣ 구조적 위험: 명령어 간에 CPU 자원을 동시에 사용하려고 할 때 발생
참고: 북스터디 - 이것이 취업을 위한 컴퓨터 과학이다 (Chapter 2-3)