커리큘럼 🫠


📃 기본 미션

p.400, 확인 문제 1번 ) 메모리 할당 방식에 대한 설명으로 올바른 것을 다음 보기에서 찾아 써 보세요.

보기) 최초 적합, 최적 적합, 최악 적합

(①) : 최초로 발견한 적재 가능한 빈 공간에 프로세스를 배치하는 방식
(②) : 프로세스가 적재될 수 있는 가장 큰 공간에 프로세스를 배치하는 방식
(③) : 프로세스가 적재될 수 있는 가장 작은 공간에 프로세스를 배치하는 방식

 

🖍 ) ① : 최초 적합, ② : 최악 적합, ③ : 최적 적합

'14-1 메모리 할당' 을 참고

 

📃 선택 미션

Ch.14 (14-3) 프로세스가 사용할 수 있는 프레임이 3개 있고, 페이지 참조열이 '2414523423'일 때 FIFO, 최적 페이지, LRU 페이지 교체 알고리즘으로 이 페이지를 참조한다면 몇 번의 페이지 폴트가 발생하는지 풀어보기

 

🖍 )

3개의 프레임에 각 알고리즘별로 페이지 참조열이 진행되었을때 페이지 폴트는 아래와 같다.

FIFO : 4번

최적페이지 : 2번

LRU 페이지 교체 : 4번

 

FIFO는 프레임에 먼저 적재된 페이지부터 교체되고

최적페이지 알고리즘은 남은 페이지 참조열 중 사용 빈도가 가장 낮을 페이지를 교체하며

LRU 페이지 교체 알고리즘은 가장 오래 사용되지 않은 페이지를 교체하였다.


1️⃣4️⃣ 가상 메모리

14-1 연속 메모리 할당

✅ 연속 메모리 할당 : 프로세스에게 연속적인 메모리 공간을 할당

 

스와핑

  • 현재 사용되지 않는 프로세스들을 보조기억장치의 일부 영역으로 쫓아내고, 빈 공간에 새 프로세스를 적재하여 실행하는 방식
  • 현재 실행되지 않는 프로세스 메모리에서 스왑 영역으로 옮겨지는 것을 스왑 아웃
  • 스왑 영역에 있던 프로세스가 다시 메모리로 옮겨오는 것을 스왑 인

SSD 중에서도 빠른걸 써야겠네 🤔

  • 프로세스들이 요구하는 메모리 공간 크기가 실제 메모리 크기보다 큰 경우에도 동시 실행 가능

 

메모리 할당

  • 프로세스는 메모리의 빈 공간에 할당되어야 한다 ➡️ 빈 공간이 여러 군데 있을 경우 세 가지 방식으로 할당 가능
  • 최초 적합, 최적 적합, 최악 적합

 

최초 적합 (first fit)

  • 운영체제가 메모리 내의 빈 공간을 순서대로 검색하다 적재할 수 있는 공간을 발견하면 그 공간에 프로세스를 배치하는 방식
  • 공간 검색을 최소화 할 수 있고 결국 빠른 할당이 가능

 

최적 적합(best fit)

  • 운영체제가 빈 공간을 모두 검색해본 뒤, 적재 가능한 가장 작은 공간에 할당하는 방식

 

최악 적합(worst fit)

  • 운영체제가 빈 공간을 모두 검색해본 뒤, 적재 가능한 가장 큰 공간에 할당

 

외부 단편화

  • 프로세스를 메모리에 연속적으로 배치하는 연속 메모리 할당은 비효율적인 방식이다
  • 외부 단편화(external fragmentation)이라는 문제가 발생하기 때문
  • 프로세스를 연속적으로 배치하여 수행 중, 먼저 종료되는 프로세스가 발생할 경우 다음과 같다.

분명 공간은 있는데 애매한게 내 방 같구만...

  • 비어있는 공간의 총 합은 50MB지만, 50MB 크기의 프로세스를 적재할 수 없다 ➡️ 외부 단편화
  • 외부 단편화 : 프로세스를 할당하기 어려울 만큼 작은 메모리 공간들로 인해 메모리가 낭비되는 현상

 

외부 단편화 해결

  1. 메모리 압축(compaction)
    • 여기저기 흩어져 있는 빈 공간들을 하나로 모으는 방식
    • 프로세스를 적당히 재배치시켜 흩어져있는 작은 빈 공간들을 하나의 큰 빈 공간으로 만드는 방법
    • 빈 공간을 합치는 과정에서 많은 오버헤드가 발생하고, 옮겨지는 프로세스들의 중단 등의 문제가 발생
  2. 가상 메모리 기법, 페이징

메모리 압축을 수행하면 내 방에 가구 놓을 공간 마련하듯 공간을 만든다.

 

14-2 페이징을 통한 가상 메모리 관리

연속 메모리 할당의 두 가지 문제점

  • 외부 단편화
  • 물리 메모리보다 큰 프로세스는 실행 불가

 

가상 메모리

  • 실행하고자 하는 프로그램을 일부만 메모리에 적재하여 실제 물리 메모리 크기보다 더 큰 프로세스를 실행할 수 있게 하는 기술
  • 크게 페이징, 세그멘테이션이 있다.
  • 대부분의 운영체제에선 페이징을 사용한다.

 

페이징(paging)

  • 외부 단편화는 각기 다른 크기의 프로세스가 메모리에 연속적으로 할당되었기 때문이다.
  • 프로세스를 일정 크기로 자르고, 이를 메모리에 불연속적으로 할당할 수 있다면 해결
  • 프로세스의 논리 주소 공간을 페이지(page)라는 일정 단위로 자른다.
  • 메모리의 물리 주소 공간을 프레임(frame)이라는 페이지와 동일한 일정한 단위로 자른다.
  • 페이지를 프레임에 할당하는 가상 메모리 관리 기법을 페이징이라 한다.

 

페이징에서의 스와핑

  • 프로세스 단위의 스왑 인, 스왑 아웃이 아닌 페이지 단위의 스왑 인(페이지 인), 스왑 아웃(페이지 아웃)
  • 메모리에 적재될 필요가 없는 페이지들은 보조기억장치로 스왑 아웃 한다.
  • 실행에 필요한 페이지들은 메모리로 스왑 인 한다.
  • 프로세스를 실행하기 위해 모든 페이지가 적재될 필요가 없다.
  • 즉, 물리 메모리보다 큰 프로세스도 실행될 수 있다. (페이지 단위로 메모리에 적재되니깐)

 

페이지 테이블

  • 프로세스가 메모리에 불연속적으로 배치되는 페이징 기법에선 CPU가 ‘다음에 실행할 명령어 위치’를 찾기 어려워진다.
  • (실제 메모리 내의 주소인) 물리 주소에 불연속적으로 배치되더라도
  • (CPU가 바라보는 주소인) 논리 주소에는 연속적으로 배치되도록 하는 방법
  • 페이지 번호와 프레임 번호를 짝지어 주는 일종의 이정표 (프로세스마다 존재해서 짝지어 주는 이정표)
  • 물리적으로는 분산되어 저장되어 있더라도 CPU 입장에서 바라본 논리 주소는 연속적으로 보임
  • CPU는 그저 논리 주소를 순차적으로 실행하면 될 뿐이다.

 

내부 단편화

  • 페이지 크기가 10KB, 프로세스 크기가 108KB일 경우
  • 2KB 만큼의 내부 단편화가 발생할 수 있다.
  • 하나의 페이지 크기보다 더 작은 크기로 발생하는 메모리 낭비

 

PTBR

  • 프로세스마다 페이지 테이블이 있다.
  • 각 페이지 테이블은 CPU 내의 프로세스 테이블 베이스 레지스터(PTBR)가 가리킨다.

 

TLB

  • 페이지 테이블이 메모리에 위치하면 프로세스 실행과정에서 메모리에 접근하는 시간이 두 배가 된다.
  • 메모리에 접근하는 시간을 줄이기 위해 CPU 옆에 (일반적으로 MMU내에) TLB(Translation Lookaside Buffer)라는 페이지 테이블의 일부를 가져와 저장하는 캐시 메모리를 이용한다.
  • CPU가 접근하려는 논리 주소가 TLB에 있다면 ➡️ TLB 히트 : 메모리 접근을 한 번한다.
  • CPU가 접근하려는 논리 주소가 TLB에 없다면 ➡️ TLB 미스 : 메모리 접근을 두 번 한다.

페이징에서의 주소 변환

  • 특정 주소에 접근하고자 할때 필요한 정보
    1. 어떤 페이지/프레임에 접근하고 싶은지에 대한 정보
    2. 접근하려는 주소가 그 페이지 혹은 프레임으로부터 얼마나 떨어져 있는지에 대한 정보
  • 페이징 시스템에서의 논리 주소 : 페이지 번호(pgae number)와 변위(offset)로 이루어져있다.
  • <페이지 번호, 변위> 는 페이지 테이블을 거쳐 <프레임 번호, 변위>로 변환된다.
  • 변위는 동일하다.

 

페이지 테이블 엔트리

  • 페이지 테이블의 각각의 행 : 페이지 테이블 엔트리(PTE)
  • 페이지 번호, 프레임 정보 외에 담기는 정보가 존재
  • 유효 비트 : 현재 해당 페이지에 접근 가능한지 여부를 나타내는 비트 정보 (메모리에 적재되어 있는지 여부를 알려준다.)
  • 유효 비트가 0인 페이지에 접근하려 할 경우 페이지 폴트(page fault)라는 인터럽트가 발생한다.
  • 보호 비트 : 페이지 보호 기능을 위해 존재하는 비트
  • 보호 비트를 읽기, 쓰기, 실행으로 권한을 나누어 저장할 수 있다.
  • 참조 비트 : CPU가 이 페이지에 접근한 적이 있는지 여부를 나타내는 비트
  • 수정 비트(=dirty bit) : CPU가 이 페이지에 데이터를 쓴 적이 있는지 여부를 알려준다.
  • 수정 비트는 페이지가 메모리에서 사라질 때 보조기억장치에 쓰기 작업을 해야 하는지, 할 필요가 없느지를 판단하기 위해 존재한다.

 

14-3 페이지 교체와 프레임 할당

 

요구 페이징

  • 처음부터 모든 페이지를 적재하지 않고 필요한 페이지만을 메모리에 적재하는 기법
  • 요구되는 페이지만 적재하는 기법
  • 아무런 페이지도 메모리에 적재하지 않은 채 무작정 실행하는 경우 ‘요구 페이징의 기본적인 양상’에 따라 페이지 폴트가 지속적으로 발생하게 되고, 점차적으로 페이지 폴트 발생 빈도가 떨어지게 된다. 이를 순수 요구 페이징(pure demand paging) 기법이라고 한다.

 

요구 페이징의 기본적인 양상

  1. CPU가 특정 페이지에 접근하는 명령어를 실행한다.
  2. 해당 페이지가 현재 메모리에 있을 경우 (유효 비트가 1일 경우) CPU는 페이지가 적재된 프레임에 접근한다.
  3. 해당 페이지가 현재 메모리에 없을 경우 (유효 비트가 0일 경우) 페이지 폴트가 발생한다.
  4. 페이지 폴트 처리 루틴은 해당 페이지를 메모리로 적재하고 유효 비트를 1로 설정한다.
  5. 다시 1번을 수행한다.

 

요구 페이징 시스템이 안정적으로 작동하기 위해 해결해야 할 묹

  1. 페이지 교체
  2. 프레임 할당

 

페이지 교체 알고리즘

  • 요구 페이징 기법으로 페이지들을 적재하다보면 메모리가 가득 차게 되며, 스와핑을 수행하게 된다.
  • 페이지 스와핑에서 스왑 아웃(페이지 아웃)을 수행할 페이지를 결정하는 방법을 페이지 교체 알고리즘이라 한다.
  • 일반적으로 페이지 폴트가 적은 알고리즘을 좋은 페이지 교체 알고리즘이라 한다.
  • 페이지 폴트 횟수는 페이지 참조열을 통해 알 수 있다.
✅ 페이지 참조열(page reference string)
 - CPU가 참조하는 페이지들 중 연속된 페이지를 생략한 페이지열
2223555337 의 페이지를 참조했다고 가정할 경우 23537이 페이지 참조열이 된다.

 

FIFO 페이지 교체 알고리즘

  • 가장 단순한 방식
  • 메모리에 가장 먼저 올라온 페이지부터 내쫒는 방식
  • 아래 그림에서 페이지 교체시에 발생하는 페이지 폴트만 고려 (순수 페이지 폴트는 생략)

  • 아이디어와 구현은 간단하지만 마냥 좋지는 않다. ➡️ 프로그램 실행 내내 사용될 페이지가 메모리에 먼저 적재되었다고 교체 당할 수 있다.

 

FIFO 페이지 교체 알고리즘 - 보완책

  • 2차 기회(second-chance) 페이지 교체 알고리즘
  • 참조 비트 1 : CPU가 한 번 참조한 적이 있는 페이지
  • 참조 비트 0 : CPU가 참조한 적이 없는 페이지
  • 참조 비트를 활용하여 FIFO 페이지 교체 알고리즘을 수행한다.
  • 내쫒으려는 대상 페이지의 참조 비트가 1일 경우 당장 내쫒지 않고 참조 비트를 0으로 만든 뒤, 현재 시간을 적재시간으로 수정한다.
  • CPU가 접근한 적이 있을 경우 한 번의 기회를 더 주는 셈
  • 메모리에 가장 오래 머무른 페이지의 참조 비트가 0일 경우 오래되었으면서 사용되지 않은 페이지므로 교체대상이 된다.

 

최적 페이지 교체 알고리즘

  • CPU에 의해 참조되는 횟수를 고려
  • 메모리에 오래 남아야할 페이지는 자주 사용될 페이지
  • 메모리에 없어도 될 페이지는 오랫동안 사용되지 않을 페이지
  • 앞으로의 사용 빈도가 가장 낮을 페이지를 교체하는 알고리즘

  • FIFO 페이지 교체 알고리즘 보타 페이지 폴트가 적어졌다
  • 가장 낮은 페이지 폴트율을 보장하는 페이지 교체 알고리즘
  • 실제 구현이 어렵다 ➡️ 사용되지 않을 페이지를 예측하는 일 🤯
  • 다른 페이지 교체 알고리즘 성능을 평가하기 위한 하한선으로 간주

 

LRU(Least-Recently-Used) 페이지 교체 알고리즘

  • 최적 페이지 교체 알고리즘은 예측의 어려움으로 구현이 어렵지만
  • LRU 페이지 교체 알고리즘은 ‘가장 오래 사용되지 않은 페이지’를 교체하는 것으로 구현이 가능하다.
  • 최근 사용되지 않은 페이지는 앞으로도 사용되지 않지 않을까? 라는 아이디어에서 출발한다.

 

기타 페이지 교체 알고리즘

  • LRU 페이지 교체 알고리즘의 파생 알고리즘들이 존재한다.

 

스레싱

  • 페이지 폴트가 자주 발생하는 이유는 근본적으로 ‘프로세스가 사용할 수 있는 프레임 자체가 적어서’ 이다.
  • 결국 프레임이 부족하면 페이지 폴트가 자주 발생하고 결과적으로 CPU의 이용률이 떨어진다.
  • 프로세스가 실행되는 시간보다 페이징에 더 많은 시간을 소요하여 성능(CPU 이용률이 저해되는 문제)를 스레싱이라 한다.
  • 동시 실행되는 프로세스의 수를 늘린다고 CPU의 이용률이 높아지는 것이 아니다. (스레싱 발생)

동시에 실행되는 프로세스를 확 늘렸더니 프레임이 부족해져서 스레싱이 발생한다

  • 스레싱이 발생하는 근본적인 이유로는 각 프로세스가 필요로 하는 최소한의 프레임 수가 보장되지 않았기 때문이다.
  • 각 프로세스가 필요로 하는 최소한의 프레임 수를 파악하고 프로세스들에게 적적한 프레임을 할당해주어야 한다.

 

균등 할당(equal allocation)

  • 가장 단순한 할당 방식
  • 모든 프로세스들에게 균등하게 프레임을 할당하는 방식
  • 프로세스별 크기가 다르기 때문에 합리적이지 않다.

 

비례 할당(proportional allocation)

  • 프로세스의 크기를 고려한 할당 방식
  • 프로세스의 크기에 비례하여 프레임을 할당한다.
  • 프로세스의 크기와 요구되는 프레임 수는 일치하지 않기 때문에 결국 실행해봐야 필요한 프레임 수를 알게 된다.
✅ 정적 할당 방식 : 프로세스의 실행과정을 고려하지 않고 프로세스의 크기나 물리 메모리의 크기 같은 고정된 값을 이용한 할당 방식 (균등 할당, 비례 할당)

 

작업 집합 모델

  • 프로세스가 실행하는 과정에서 배분할 프레임을 결정
  • 스레싱이 발생하는 이유가 빈번한 페이지 교체 때문이니 CPU가 특정 시간 동안 주로 참조한 페이지 개수만큼만 프레임을 할당하는 아이디어

 

작업 집합

  1. 프로세스가 참조한 페이지
  2. 시간 간격

특정 시간에서 참조한 페이지

 

페이지 폴트 빈도 기반 프레임 할당

  • 프로세스가 실행하는 과정에서 배분할 프레임 결정
  • 두 개의 가정에서 생겨난 아이디어
    1. 페이지 폴트율이 너무 높으면 그 프로세스는 너무 적은 프레임을 갖고 있다.
    2. 페이지 폴트율이 너무 낮으면 그 프로세스가 너무 많은 프레임을 갖고 있다.
  • 페이지 폴트율에 대해 상한선과 하한선을 정하고, 그 내부 범위 안에서만 프레임을 할당하는 방식

적당히 선을 지키는게 중요하다

✅ 동적 할당 방식 : 프로세스가 실행하는 과정을 통해서 프레임을 할당하는 방식 (작업 집합 모델, 페이지 폴트 빈도 기반 프레임 할당)

1️⃣5️⃣ 파일 시스템

 

15-1 파일과 디렉터리

파일 시스템(file system)

  • 파일과 디렉터리를 관리하는 운영체제 내의 프로그램
  • 파일과 디렉터리를 다루어 주는 프로그램
  • 한 컴퓨터 내에 여러 파일 시스템을 이용할 수도 있다.

 

파일과 디렉터리

  • 보조기억장치의 데이터 덩어리

 

파일

  • 보조기억장치에 저장된 관련 정보의 집합
  • 의미 있고 관련 있는 정보를 모은 논리적 단위
  • 파일을 이루는 정보 = 파일을 실행하기 위한 정보 + 부가 정보(= 속성, 메타 데이터)

파일의 속성

 

  • 유형 : 운영체제가 인식하는 파일의 종류, 파일 유형을 알리기 위해 가장 흔히 사용하는 방식이 파일 이름 뒤에 붙는 확장자

 

파일 연산을 위한 시스템 호출

  • 파일을 다루는 모든 작업은 운영체제에 의해 이뤄진다.
  • 파일을 다루기 위해 운영체제는 파일 연산을 위한 시스템 호출을 제공한다.
  1. 파일 생성
  2. 파일 삭제
  3. 파일 열기
  4. 파일 닫기
  5. 파일 읽기
  6. 파일 쓰기

 

디렉터리

  • 윈도우에서는 폴더(folder)라고 부른다.
  • 과거 운영체제에서는 하나의 디렉터리만 존재 : 1단계 디렉터리
  • 최근 운영체제는 대부분 여러 계층으로 파일 및 폴더를 관리하는 트리 구조 디렉터리 - 최상위 디렉터리(루트 디렉터리, /), 서브 디렉터리가 존재한다.

 

경로

  • 디렉터리를 이용해서 파일/디렉터리의 위치, 나아가 이름까지 특정 지을 수 있는 정보
  • 절대 경로와 상대 경로가 존재
  • 절대 경로 : 루트 디렉터리에서 자기 자신까지 이르는 고유한 경로
  • 상대 경로 : 현재 디렉터리부터 자기 자신까지 이르는 경로
✅ 같은 디렉터리에는 동일한 이름의 파일이 존재할 수 없지만, 서로 다른 디렉터리에는 동일한 이름의 파일이 존재할 수 있다.

 

디렉터리 엔트리

  • 사실 많은 운영체제에서는 디렉터리를 그저 ‘특별한 형태의 파일’로 간주한다.
  • 디렉터리는 그저 ‘포함된 정보가 조금 특별한 파일’이다.
  • 파일의 내부에는 파일과 관련된 정보들이 있다면,
  • 디렉터리의 내부에는 해당 디렉터리에 담겨 있는 대상과 관련된 정보들이 담겨 있다. (보통 테이블 형태로 구성)
  • 디렉터리 엔트리에 담기는 정보는 디렉터리에 포함된 대상의 이름, 그 대상이 보조기억장치 내에 저장된 위치(를 유추할 수 있는 정보)가 있다.

  • 디렉터리 엔트리에 파일 속성을 명시하는 경우도 있다.

 

15-2 파일 시스템

 

파티셔닝(partitioning)

  • 저장 장치의 논리적인 영역을 구획하는 작업
  • 파티셔닝 작업을 통해 나누어진 영역 하나하나를 파티션(partition)이라 한다.

 

포매팅(formatting)

  • 저장 장치를 삭제하는 것 ➡️ 정확한 표현이 아님
  • 파일 시스템을 설정하여 어떤 방식으로 파일을 관리할지 결정, 새로운 데이터를 쓸 준비하는 작업
  • USB 포매팅시 파일 시스템을 골라 포매팅 한다. 즉 파일 시스템은 포매팅할 때 결정된다.
  • 파일 시스템에는 여러 종류가 있고, 파티션마다 다른 파일 시스템을 설정할 수도 있다.
✅ 포매팅까지 완료하여 파일 시스템을 설정하였다면, 파일과 디렉터리 생성이 가능해진다.

 

파일 할당 방법

  • 포매팅까지 끝난 하드 디스크에 파일 저장하기
  • 운영체제는 파일/디렉터리를 블록 단위로 읽고 쓴다.
  • 하나의 파일이 보조기억장치에 저장될 때에는 여러 블록에 걸쳐 저장된다.
  • 파일을 보조기억장치에 할당하는 두 가지 방법 : 연속 할당, 불연속 할당
  • 불연속 할당은 연결 할당과 색인 할당으로 나누어진다.
✅ 하드 디스크의 가장 작은 저장 단위는 섹터이지만 보통 블록 단위로 읽고 쓴다.

 

연속 할당

  • 이름 그대로 보조기억장치 내 연속적인 블록에 파일 할당
  • 연속된 파일에 접근하기 위해 파일의 첫 번째 블록 주소와 블록 단위의 길이만 알면 된다.
  • 디렉터리 엔트리 : 파일 이름 & 첫번째 블록 주소 & 블록 단위 길이 명시

  • 구현이 단순하다는 장점이 있지만 외부 단편화를 야기할 수 있다.

 

불연속 할당 - 연결 할당

  • 각 블록의 일부에 다음 블록의 주소를 저장하여 각 블록이 다음 블록을 가리키는 형태로 할당
  • 파일을 이루는 데이터 블록을 연결 리스트로 관리
  • 불연속 할당의 일종 : 파일이 여러 블록에 흩어져 저장되어도 무방
  • 디렉터리 엔트리 : 파일 이름 & 첫번째 블록 주소 & 블록 단위의 길이

  • 외부 단편화 문제를 해결하지만 단점이 존재
    1. 반드시 첫 번째 블록부터 하나씩 차례대로 읽어야 한다. 즉 임의접근 속도가 느리다.
    2. 하드웨어 고장이나 오류 발생 시 해당 블록 이후 블록은 접근할 수 없다.

 

불연속 할당 - 색인 할당

  • 파일의 모든 블록 주소를 색인 블록이라는 하나의 블록에 모아 관리하는 방식
  • 파일 내 임의의 위치에 접근하기 용이하다.
  • 디렉터리 엔트리 : 파일 이름 & 색인 블록 주소

 

FAT 파일 시스템

  • 연결 할당 기반 파일 시스템
  • 연결 할당의 단점을 보완한 파일 시스템이다.
  • 파일 할당 테이블(FAT, File Allocation Table)에 각 블록에 포함된 다음 블록 주소를 한데 모아 관리한다.
  • FAT가 메모리에 캐시될 수 있기 때문에 캐시될 경우 느린 임의 접근 속도를 개선할 수 있다.
  • 디렉터리 엔트리에는 파일의 속성까지 같이 명시된다.

 

유닉스 파일 시스템

  • 색인 할당 기반 파일 시스템
  • 색인 블록을 i-node 라고 부른다.
  • i-node 에는 파일 속성 정보와 열다섯 개의 블록 주소가 저장될 수 있다.
  • i-node의 크기보다 큰 블록의 파일을 저장하기 위해서 유닉스 파일 시스템은 다음과 같이 해결한다.
    1. 블록 주소 중 열두 개에는 직접 블록 주소를 저장한다. (직접 블록 : 파일 데이터가 저장된 블록)
    2. 1번으로 충분하지 않다면 13번째 주소에 단일 간접 블록 주소를 저장한다. (단일 간접 블록 : 파일 데이터를 저장한 블록 주소가 저장된 블록)
    3. 2번으로 충분하지 않다면 14번째 주소에 이중 간접 블록 주소를 저장한다. (이중 간접 블록 : 단일 간접 블록들의 주소를 저장하는 블록)
    4. 3번으로 충분하지 않다면 15번째 주소에 삼중 간접 블록 주소 저장 (삼중 간접 블록 : 이중 간접 블록들의 주소를 저장하는 블록)

커리큘럼 🫠


📃 기본 미션

p.363, 확인 문제 1번 ) 뮤텍스 락과 세마포에 대한 설명으로 옳지 않은 것을 고르세요.

① 뮤텍스 락은 임계 구역을 잠근 뒤 임계 구역에 진입함으로써 상호 배제를 위한 동기화를 이룹니다.
② 세마포는 공유 자원이 여러 개 있는 상황에서도 이용할 수 있습니다.
③ 세마포를 이용해 프로세스 실행 순서 제어를 위한 동기화도 이룰 수 있습니다.
④ 세마포를 이용하면 반드시 바쁜 대기를 해야 합니다.

 

🖍 ) ④, 프로세스를 대기 상태로 변경하여 CPU 사이클에서 제외하는 방법도 존재한다.

📃 선택 미션
Ch.12 (12-1) 임계 구역, 상호 배제 개념을 정리하기

 

🖍 )

임계 구역 : 레이스 컨디션이 발생할 수 있는 코드 영역

상호 배제 : 특정 프로세스가 공유자원을 사용하고 있을 경우, 다른 프로세스가 해당 공유자원을 사용하지 못하게 배제하는 기법,

프로세스들이 번갈아가며 자원을 사용하게끔 임계 구역에 한 프로세스의 입장을 허락하게 함

자세한 내용 확인하러 가기🧚‍♀️


1️⃣2️⃣ 프로세스 동기화

12-1 동기화란

동기화의 의미

  • 공동의 목적을 위해 동시에 수행되는 프로세스는 서로 데이터를 주고받으며 협력하며 실행될 수 있다.
  • 자원의 일관성을 보장하기 위해서 (프로세스) 동기화가 필수적이다.
  • 프로세스들의 수행 시기를 맞추는 것을 동기화라고 한다.
    • 실행 순서 제어 : 프로세스를 올바른 순서대로 실행하기
    • 상호 배제 : 동시에 접근해서는 안 되는 자원에 하나의 프로세스만 접근하게 하기
  • 실행의 문맥을 갖는 모든 대상은 동기화 대상이기에 스레드도 동기화 대상이다.

 

실행 순서 제어를 위한 동기화 : reader writer problem

  • Writer : Book.txt 파일에 값을 저장하는 프로세스
  • Reader : Book.txt 파일에 저장된 값을 읽어들이는 프로세스
  • Wirter 프로세스와 Reader 프로세스가 무작정 실행되면? ➡️ 😱
  • 실행의 순서를 지켜 실행 될 경우 의도성을 가진채로 실행 가능 (예외적인 상황 발생을 억제할 수 있다)
  • ex) Reader 프로세스는 ‘Book.txt 안에 값이 존재한다’는 특정 조건이 만족되어야만 실행 가능

 

상호 배제를 위한 동기화 : Bank account problem

  • 공유가 불가능한 자원의 동시 사용을 피하기 위한 동기화
  • 한번에 하나의 프로세스만 접근해야 하는 자원에 동시 접근을 피하기 위한 동기화
  • 하나의 프로세스에서 자원에 접근 중일때 같은 자원을 접근하는 나머지 프로세스는 대기하여야 한다.
  • ex) 은행 계좌의 조작 프로세스 (계좌의 값을 읽어들여서 계산 후 저장하는 과정에서 동기화가 이루어지지 않으면 예상치 못한 값이 저장될 수 있다.)

 

상호 배제를 위한 동기화 : Producer & Consumer problem

  • 물건을 계속해서 생산하는 생산자 (producer, 프로세스 혹은 스레드)
  • 물건을 계속해서 소비하는 소비자 (consumer, 프로세스 혹은 스레드)
  • ‘총합’ 변수를 공유
  • 생산자와 소비자를 무작정 100,000번 실행하면 총합의 변수 값이 10이 아닌 예상 밖의 값이 된다.
  • 동기화가 되지 않았기 때문에 발생한 문제로 동시에 접근해서는 안되는 자원(총합)에 동시에 접근해서 발생한 문제

 

공유 자원(shared resource)과 임계 구역 (critical section)

  • 공유 자원 : 여러 프로세스 혹은 스레드가 공유하는 자원 (ex : 전역 변수, 파일, 입출력장치, 보조기억장치, …)
  • 임계 구역 : 동시에 실행하면 문제가 발생하는 자원에 접근하는 코드 영역 (ex : 예시의 ‘총합’ 변수, ‘잔액’ 변수,…)
  • 임계 구역에 진입하고자 하면 진입한 프로세스 이외에는 대기해야 한다. (동기화를 위해)

아주 중요함... 🫢

 

  • 레이스 컨디션(race condition) : 임계 구역에 동시에 접근하여 자원의 일관성이 깨지는 상태
  • 즉 레이스 컨디션이 발생할 수 있는 코드 영역을 임계 구역이라고 한다.

 

운영체제가 임계구역 문제를 해결하는 세 가지 원칙

(’상호 배제를 위한 동기화’를 지키기 위한 세 가지 원칙)

  1. 상호 배제 (mutual exclusion)
    • 한 프로세스가 임계 구역에 진입했다면 다른 프로세스는 들어올 수 없다.
  2. 진행 (progress)
    • 임계 구역에 어떤 프로세스도 진입하지 않았다면 진입하고자 하는 프로세는 들어갈 수 있어야 한다.
  3. 유한 대기 (bounded waiting)
    • 한 프로세스가 임계 구역에 진입하고 싶다면 언젠가는 임계 구역에 들어올 수 있어야 한다
    • 임계 구역에 들어오기 위해 무한적 대기해서는 안 된다.

 

12-2 동기화 기법

뮤텍스 락 (Mutex lock)

  • 상호 배제를 위한 동기화 도구(자물쇠 역할)
  • 뮤텍스 락의 단순한 형태 : 전역 변수 하나, 함수 두 개
    • 자물쇠 역할 : 프로세스들이 공유하는 전역 변수 Lock
    • 임계 구역을 잠그는 역할 : acquire 함수
    • 임계 구역의 잠금을 해제하는 역할 : release 함수
  • acquire 함수
    • 프로세스가 임계 구역에 진입하기 전에 호출
    • 임계 구역이 잠겨 있다면 ➡️ 임계 구역이 열릴 때까지(lock이 false가 될 때까지) 임계 구역을 반복적으로 확인한다.
    • 임계 구역이 열려 있다면 ➡️ 임계 구역을 잠근다 (lock을 true로 바꾸기)
  • release 함수
    • 임계 구역에서의 작업이 끝나고 호출
    • 현재 잠긴 임계 구역을 열기 (lock을 false로 바꾸기)
✅ 바쁜 대기 (busy waiting) : lock이 잠겨있는지 계속 확인해보는 것 ➡️ 좋은 방식은 아님

스도 코드 형태로 나타낸 뮤텍스 락 🔒

 

세마포 (Semaphore)

  • 좀 더 일반화된 방식의 동기화 도구
  • 뮤텍스 락은 하나의 공유 자원에 접근하는 프로세스를 상정한 방식 ↔️ 세마포는 공유 자원이 여러 개 있는 경우에도 적용 가능한 방식
  • 세마포의 종류로 이진 세마포 (binary semaphore), 카운팅 세마포 (counting semaphore)가 있지만, 이진 세마포는 뮤텍스 락과 비슷한 개념이고 일반화된 개념인 카운팅 세마포를 중점으로 본다.
  • 임계 구역 앞에서 멈춤 신호를 받으면 잠시 기다리기
  • 임계 구역 앞에서 가도 좋다는 신호를 받으면 임계 구역 진입
  • 세마포의 단순한 형태 : 전역 변수 하나, 함수 두 개
    • 임계 구역에 진입할 수 있는 프로세스의 개수(사용 가능한 공유 자원의 개수)를 나타내는 전역 변수 S
    • 임계 구역에 들어가도 좋은지, 기다려야 할지를 알려주는 wait 함수
    • 임계구역 앞에서 기다리는 프로세스에 ‘이제 가도 좋다’고 신호를 주는 signal 함수
  • 허용된 S의 값으로 프로세스 실행이 결정 된다.

스도 코드 형태로 나타낸 세마포 ⚒️

✅ Mutex lock 과 동일하게 busy waiting 이다. ➡️ CPU 사이클 낭비

해결 방법
사용할 수 있는 자원이 없을 경우 대기 상태로 만듦, CPU 사이클이 필요없는 상태 (해당 프로세스의 PCB를 대기 큐에 삽입) 사용할 수 있는 자원이 생겼을 경우 대기 큐의 프로세스를 준비 상태로 만듦 (해당 프로세스의 PCB를 대기 큐에서 꺼내 준비 큐에 삽입)

 

세마포를 활용한 실행 순서 동기화

  • 세마포의 변수 S를 0으로 두고,
  • 먼저 실행할 프로세스 뒤에 signal 함수
  • 다음에 실행할 프로세스 앞에 wait 함수를 붙이면 된다.

 

모니터

  • 사용자(개발자)가 다루기 편리한 동기화 도구
  • 상호 배제를 위한 동기화
    • 인터페이스를 위한 큐
    • 공유자원에 접근하고자 하는 프로세스를 (인터페이스를 위한) 큐에 삽입
    • 큐에 삽입된 순서대로 (한 번에 하나의 프로세스만) 공유 자원 이용

공유 자원의 연산은 큐에서 인터페이스를 통해 하나씩 이용한다. 😲

  • 실행 순서 제어를 위한 동기화
    • 조건 변수 (condition variable) 이용
    • 프로세스나 스레드의 실행 순서를 제어하기 위해 사용하는 특별한 변수
    • 조건변수.wait() : 대기 상태로 변경, 조건 변수에 대한 큐에 삽입
    • 조건변수.signal() : wait()으로 대기 상태로 접어든 조건변수를 실행 상태로 변경

상호 배제를 위한 큐와 조건 변수에 대한 큐가 다름을 인지할 것 😚

  • 모니터 안에는 하나의 프로세스만이 있을 수 있다.
    • wait()를 호출했던 프로세스는 signal()을 호출한 프로세스가 모니터를 떠난 뒤에 수행을 재개하는 방법
    • signal()을 호출했던 프로세스의 실행을 일시 중단하고 자신이 실행된 뒤 다시 signal()을 호출한 프로세스의 수행을 재개하는 방법
  1. 특정 프로세스가 아직 실행될 조건이 되지 않았을 때에는 wait를 통해 실행을 중단한다.
  2. 특정 프로세스가 실행될 조건이 충족되었을 때에는 signal을 통해 실행을 재개한다.

 


1️⃣3️⃣ 교착 상태

13-1 교착 상태란

결혼식장에서 본 풍경... (수저가 없어진건 옆사람이 범인 🕵️)

 

교착상태

  • 일어나지 않을 사건을 기다리며 진행이 멈춰 버리는 현상
  • 프로세스들이 서로가 점유한 자원을 기다리고 멈춰 ✋!!! 하고 있음

 

교착 상태를 해결하기 위해서는?

  1. 교착 상태가 발생했을 때의 상황을 정확히 표현해보기
  2. 교착 상태가 일어나는 근본적인 이유를 이해하기

 

자원 할당 그래프

  • 교착 상태 발생 조건 파악 가능
  • 어떤 프로세스가 어떤 자원을 할당 받아 사용 중인지 확인 가능
  • 어떤 프로세스가 어떤 자원을 기다리고 있는지 확인 가능
  • 자원 할당 그래프 그리는 방법
    1. 프로세스는 원으로, 자원의 종류는 사각형으로 표현
    2. 사용할 수 있는 자원의 개수는 자원 사각형 내에 점으로 표현
    3. 프로세스가 어떤 자원을 할당 받아 사용 중이라면 자원에서 프로세스를 향해 화살표를 표시
    4. 프로세스가 어떤 자원을 기다리고 있다면 프로세스에서 자원으로 화살표를 표시
  • 교착 상태가 일어난 그래프의 특징
    • 자원 할당 그래프가 원의 형태를 띄고 있다.

 

교착 상태 발생할 조건

  1. 상호 배제 : 한 프로세스가 사용하는 자원을 다른 프로세스가 사용할 수 없는 상태
  2. 점유와 대기 : 자원을 할당 받은 상태에서 다른 자원을 할당 받기를 기다리는 상태
  3. 비선점 : 어떤 프로세스도 다른 프로세스의 자원을 강제로 빼앗지 못하는 상태
  4. 원형 대기 : 프로세스들이 원의 형태로 자원을 대기하는 상태
  • 네 가지 조건 중 하나라도 만족하지 않으면 교착 상태가 발생하지 않음
  • 네 가지 조건을 모두 만족하면 교착 상태가 발생할 수 있음

 

13-2 교착 상태 해결 방법

교착 상태 해결

  • 예방
  • 회피
  • 검출 후 회복

 

교착 상태 예방

  • 애초에 교착 상태가 발생하지 않도록 한다.
  • 교착 상태 발생 조건(상호 배제, 점유와 대기, 비선점, 원영 대기) 중 하나를 없애버리기
  • 상호 배제를 없애면… : 모든 자원을 공유하게 만든다? ➡️ 현실적으로 불가능
  • 점유와 대기를 없애면… : 특정 프로세스에 자원을 모두 할당하거나, 아예 할당하지 않는 방식으로 배분 ➡️ 자원의 활용률이 떨어질 수 있음
  • 비선점 조건을 없애면… : 선점이 가능한 자원 (CPU)에 한해서 효과적 ➡️ 모든 자원이 선점 가능한 것은 아니다.
  • 원형 대기 조건을 없애면… : 모든 자원에 번호를 붙이고, 오름차순으로 자원을 할당하는 방식 ➡️ 모든 자원에 번호를 붙이는 것이 어려움, 어떤 자원에 어떤 번호를 붙이느냐에 따라 자원 활용률이 달라짐
  • 교착 상태 해결을 위한 예방은 교착 상태가 발생하지 않음은 보장할 수 있으나 부작용이 따라온다.

 

교착 상태 회피

  • 교착 상태를 무분별한 자원 할당으로 인해 발생했다고 간주 (포크가 무제한이라면 교착 상태가 발생하지 않는다)
  • 교착 상태가 발생하지 않을 만큼 조심스럽게 할당하기
  • 배분할 수 있는 자원의 양을 고려하여 교착 상태가 발생하지 않을 만큼만 자원 배분
  • 안전 순서열 : 교착 상태 없이 안전하게 프로세스들에 자원을 할당할 수 있는 순서
  • 안전 상태 : 교착 상태 없이 모든 프로세스가 자원을 할당 받고 종료될 수 있는 상태 (안전 순서열이 있는 상태)
  • 불안전 상태 : 교착 상태가 발생할 수도 있는 상태 (안전 순서열이 없는 상태)
  • 안전 상태에서 안전 상태로 움직이는 경우에만 자원을 할당하는 방식
  • 항시 안전 상태를 유지하도록 자원을 할당하는 방식
  • 추가 학습 : 은행원 알고리즘

 

교착 상태 검출 후 회복

  • 교착 상태의 발생을 인정하고 사후에 조치하는 방식
  • 프로세스가 자원을 요구하면 일단 할당, 교착 상태가 검출되면 회복
  • 검출 후 회복 방식 2가지
    1. 선점을 통한 회복
      • 교착 상태가 해결될 때까지 한 프로세스씩 자원을 몰아주는 방식
    2. 프로세스 강제 종료를 통한 회복
      • 교착 상태에 놓인 프로세스 모두 강제 종료 (작업 내역을 잃을 위험이 존재한다)
      • 교착 상태가 해결될 때까지 한 프로세스씩 강제 종료 (교착 상태가 없어졌는지 확인하는 과정에서 오버헤드 발생)

 

교착 상태 무시

  • 타조 알고리즘 : 드물게 발생하는 잠재적 문제를 무시로 대처하는 방식
  • 문제 발생의 빈도나 심각성에 따라 때때로 적합한 방식일 수도 있다.

 


 

 

주절주절 : 📖 ➡️ 👀 ➡️ 🤯 ➡️ ☠️ ➡️ 👻 ➡️ 📖

커리큘럼 🫠


📃 기본 미션1
p.304, 확인 문제 1번 ) 다음은 프로세스 상태를 보여주는 프로세스 상태 다이어그램입니다. ① 부터 ⑤ 까지 올바른 상태를 적어 보세요.

🖍 )
① = 생성 상태
② = 준비 상태
③ = 실행 상태
④ = 종료 상태
⑤ = 대기 상태

📃 선택 미션
Ch.11 (11-2) 준비 큐에 A, B, C, D 순으로 삽입 될 때 선입 선처리, 최단 작업 우선, 라운드 로빈, 우선순위 스케줄링에서 어떤 프로세스로 CPU를 할당 받는지 정리해보기
🖍 )
1. 선입 선처리 : 준비 큐에 먼저 적재된 순서대로 CPU를 할당 받는다. (FCFS)
2. 최단 작업 우선 : CPU 사용시간이 가장 짧은 프로세스부터 가장 긴 프로세스까지 순차적으로 할당 받는다. (SJF)
3. 라운드 로빈 : 정해진 타임슬라이스만큼씩 프로세스들에게 CPU를 할당하는데, 할당 순서는 준비 큐에 먼저 적재된 순서대로...
4. 우선순위 스케줄링 : 프로세스들에 우선순위를 부여하고 우선순위가 높은 프로세스부터 순차적으로 실행한다.
자세한 내용 확인하러 가기🧚‍♀️

수정) 준비 큐에 A, B, C, D 순으로 삽입되었다고 가정했을 때, 선입 선처리 스케줄링 알고리즘을 적용하면 어떤 프로세스 순서대로 CPU를 할당 받는지 풀어보기
🖍 )
선입 선처리 스케줄링 알고리즘은 준비 큐에 적재된 순서대로 CPU를 할당 받는다. 고로 삽입된 순서인 A, B, C, D 의 순서로 CPU를 할당 받는다.
이렇게 할당받아 작업을 수행하는 와중에 준비큐에 적재된 프로세스들의 기다리는 시간이 매우 길어질 수 있다. 그런 호위 효과를 해결하기 위해 다양한 스케줄링 알고리즘이 존재한다. (위의 링크를 눌러봐!! 🤭)


9️⃣ 운영체제 시작하기

09-1 운영체제를 알아야 하는 이유

운영체제란

  • 자원/시스템 자원 : 프로그램 실행에 있어 마땅히 필요한 요소 (컴퓨터의 네 가지 핵심 부품 포함)
  • 실행할 프로그램에 필요한 자원을 할당하고 프로그램이 올바르게 실행되도록 돕는 특별한 프로그램
✅ 응용 프로그램 : 사용자가 특정 목적을 위해 사용하는 일반적인 프로그램


운영체제의 메모리 관리

  • 운영체제 또한 메모리에 적재되지만, 매우 특별한 프로그램이므로 항상 컴퓨터가 부팅될 때 메모리 내 커널 영역에 적재된다.
  • 응용 프로그램의 경우 메모리내에 사용자 영역에 적재된다.

넌 이미 적재되어 있다. 🫣


운영체제의 CPU 관리

  • 사용자가 인지하지 못하는 아주 미세한 단위의 시간마다 각종 프로그램을 번갈아 실행 ➡️ 동시에 실행되는 것처럼 느낌
  • 어떤 프로그램부터 CPU를 사용하게 할지, 얼마나 오랫동안 CPU를 이용하게 할지 등의 문제를 운영체제가 해결해준다.


운영체제의 입출력장치 관리

  • 입출력 장치를 이용하는 응용프로그램의 제어와 입출력 장치 간의 자원을 관리한다.
  • 운영체제는 응용 프로그램과 하드웨어 사이에서 응용 프로그램에 필요한 자원을 할당하고, 응용 프로그램이 올바르게 실행되도록 관리하는 역할을 수행한다.

중요하다 중요해 🤩


운영체제를 알아야 하는 이유

  • 하드웨어를 조작하는 코드를 직접 개발해야한다!! ➡️ 으악!! 👻
  • 운영체제는 사용자를 위한 프로그램이 아니다. ➡️ 프로그램을 위한 프로그램 🤔
  • 프로그램을 만드는 개발자는 운영체제를 알아야 한다.
  • 문제 해결 능력과 관련 : 개발자가 작성한 프로그램이 하드웨어 상에서 어떻게 작동하는지를 파악하는 것은 운영체제 ➡️ 운영체제를 이해함으로써 하드웨어와 프로그램을 더 깊이 이해할 수 있다.
  • 운영체제가 알려주는 오류 메세지에 대한 깊은 이해 가능

 

09-2 운영체제의 큰 그림

커널

  • 운영체제는 현존하는 프로그램 중 규모가 가장 큰 프로그램 중 하나
  • 운영체제가 제공하는 가장 핵심적인 서비스 : 자원에 접근하고 조작하는 기능, 프로그램이 올바르고 안전하게 실행되게 하는 기능
  • 운영체제의 핵심 서비스를 담당하는 부분을 커널이라고 한다.
✅ 운영체제에는 속하는데 커널에는 속하지 않는 기능? ➡️ 유저 인터페이스 (UI; User Interface)
사용자와 컴퓨터 간의 통로일 뿐 운영체제의 핵심 기능(커널)은 아님
  • 운영체제는 사용자가 실행하는 응용 프로그램이 하드웨어 자원에 직접 접근하는 것을 방지하여 자원을 보호한다.
  • 응용 프로그램이 자원에 접근하려면 운영체제에 도움을 요청 (= 운영체제의 코드를 실행) 해야한다.


이중 모드

  • CPU가 명령어를 실행하는 모드를 크게 사용자 모드와 커널 모드로 구분하는 방식
  • 사용자 모드
    1. 운영체제 서비스를 제공받을 수 없는 실행 모드
    2. 커널 영역의 코드를 실행할 수 없는 실행 모드
    3. 자원 접근 불가
  • 커널 모드
    1. 운영체제의 서비스를 제공받을 수 있는 실행 모드
    2. 자원 접근을 비롯한 모든 명령어 실행 가능
✅ 플래그 참조 : 슈퍼바이저 플래그 (https://goming0925.tistory.com/16)


시스템 호출

  • 운영체제 서비스를 제공받기 위해 커널 모드로 전환하여 실행하기 위해 호출
  • 일종의 소프트웨어 인터럽트
  • 시스템 호출이 처리되는 방식은 하드웨어 인터럽트 처리 방식과 유사하다.

커널 모드로 바꾸는 방법은 DM으로... 🙏


운영체제의 핵심 서비스

  1. 프로세스 관리
    • 프로세스 == 실행 중인 프로그램
    • 수많은 프로세스들이 동시에 실행된다.
    • 윈도우에서 작업 관리자에 출력되는 프로세스!
    • 프로세스마다 상태, 상황, 사용하고자 하는 자원이 다르다.
    • 동시다발적으로 생성/실행/삭제되는 다양한 프로세스를 일목요연하게 관리한다. ➡️ 프로세스와 스레드, 프로세스 동기화, 교착상태 해결
  2. 자원 접근 및 할당
    • CPU (CPU 스케줄링 : 어떤 프로세스를 먼저, 얼마나 오래 실행할까?)
    • 메모리 (페이징, 스와핑, …)
    • 입출력장치
  3. 파일 시스템 관리
    • 관련된 정보를 파일이라는 단위로 저장 장치에 보관
    • 파일들을 묶어 폴더(디렉터리) 단위로 저장 장치에 보관
✅ 운영체제의 어떤 기법에 의해서 모든 프로세스가 메모리에 올라와 있지 않을 수도 있다?! ➡️ 페이징, 스와핑

🔟 프로세스와 스레드

10-1 프로세스 개요

프로세스

  • 실행 중인 프로그램
  • 보조기억장치에 저장된 프로그램을 메모리에 적재하고 실행하는 과정 : ‘프로세스 생성 과정’

포그라운드 프로세스 (foreground process)

  • 사용자가 볼 수 있는 공간에서 실행되는 프로세스

백그라운드 프로세스 (background process)

  • 사용자가 볼 수 없는 공간에서 실행되는 프로세스
  • 사용자와 직접 상호작용이 가능한 백그라운드 프로세스
  • 사용자와 상호작용하지 않고 그저 정해진 일만 수행하는 프로세스 : 데몬(daemon), 서비스(service)

프로세스 제어 블록

  • 모든 프로세스는 실행을 위해 CPU가 필요하다. 하지만 CPU의 자원은 한정되어있다.
  • 프로세스들은 돌아가며 한정된 시간 만큼만 CPU 이용
    • 자신의 차례에 정해진 시간만큼 CPU 이용한다.
    • 타이머 인터럽트가 발생하면 차례를 양보한다.
  • 빠르게 번갈아 수행되는 프로세스들을 관리하기 위해 사용되는 자료구조가 프로세스 제어 블록 (이하 PCB)
    • 프로세스 관련 정보를 저장하는 자료 구조
    • 마치 상품에 달린 태그와 같은 정보
    • 프로세스 생성 시 커널 영역에 생성, 종료 시 폐기

프로세스의 태그 PCB, 이거 떼면 반품 못해요? 🤔

  • PCB에 담기는 대표적인 정보 (운영체제마다 차이가 있음)
    1. 프로세스 ID (=PID)
    2. 레지스터 값
    3. 프로세스 상태
    4. CPU 스케줄링 정보
    5. 메모리 정보
    6. 사용한 파일과 입출력장치 정보

프로세스 ID

  • 특정 프로세스를 식별하기 위해 부여하는 고유한 번호 (학교의 학번, 회사의 사번)

레지스터 값

  • 프로세스는 자신의 실행 차례가 오면 이전까지 사용한 레지스터 중간 값을 모두 복원 ➡️ 실행 재개를 위한 값
  • 프로그램 카운터, 스택 포인터 … 등

프로세스 상태

  • 입출력 장치를 사용하기 위해 기다리는 상태
  • CPU를 사용하기 위해 기다리는 상태
  • CPU를 이용 중인 상태

CPU 스케줄링 정보

  • 프로세스가 언제, 어떤 순서로 CPU를 할당받을지에 대한 정보

메모리 관리 정보

  • 프로세스가 어느 주소에 저장되어 있는지에 대한 정보
  • 페이지 테이블 정보 (지금으로서는 ‘메모리 주소를 알 수 있는 정보가 담기는구나’ 라고 이해)

사용한 파일과 입출력장치 정보

  • 할당된 입출력장치, 사용 중인(열린) 파일의 정보

문맥 교환 (Context switching)

  • 한 프로세스 (예시 : 프로세스 A)에서 다른 프로세스 (예시 : 프로세스B)로 실행 순서가 넘어가면 어떤 작업이 이루어지는지?
  1. 기존에 실행되던 프로세스 A는 지금까지의 중간 정보를 백업해야한다.
  2. 뒤이어 실행할 프로세스 B의 문맥을 복구 ➡️ 자연스럽게 실행 중인 프로세스가 바뀜
  • 이처럼 기존의 실행 중인 프로세스 문맥을 백업하고, 새로운 프로세스 실행을 위해 문맥을 복구하는 과정을 문맥 교환(context switching) 이라 한다.
  • 여러 프로세스가 끊임없이 빠르게 번갈아 가며 실행되는 원리이다.

프로세스를 번갈아가며 실행할때 발생하는 문맥 교환

문맥(context)

  • 프로그램 카운터 등 각종 레지스터 값, 메모리 정보, 열었던 파일, 사용한 입출력장치 등
  • 이러한 중간 정보를 문맥(context)라고 한다.
  • 다음 차례가 왔을 때 실행을 재개하기 위한 정보이다.
  • 실행 문맥을 백업해두면 언제든 해당 프로세스의 실행을 재개할 수 있다.
✅ PCB는 커널영역에서 프로세스를 관리하기 위한 자료 구조 ➡️ 사용자 영역에서는?


프로세스의 메모리 영역

  • 사용자 영역에 저장되는 프로세스는 크게 코드 영역 (=텍스트 영역), 데이터 영역, 힙 영역, 스택 영역 4개이다.

저는 데이터 영역이랑 코드 영역을 건드리는 미천한 나무늘보... 🦥


코드 영역 (= 텍스트 영역)

  • 실행할 수 있는 코드, 기계어로 이루어진 명령어 저장
  • 데이터가 아닌 CPU가 실행할 명령어가 담기기에 쓰기가 금지된 영역 (일반적으로 read-only)


데이터 영역

  • 잠깐 썼다가 없앨 데이터가 아닌 프로그램이 실행되는 동안 유지할 데이터 저장
  • 예시 : 전역 변수


힙 영역

  • 프로그램을 만드는 사용자, 즉 프로그래머가 직접 할당할 수 있는 저장공간
  • 프로그래밍에서 메모리 공간을 힙 영역으로 할당했다면 다시 반환되어야 함 ➡️ 프로그래밍 언어가 알아서 해주는 경우가 있음 : 가비지 컬렉션
  • 메모리 공간을 반환하지 않는다면 메모리 내에 계속 남아 메모리 낭비를 초래 ➡️메모리 누수 (Memory leak)


스택 영역

  • 데이터가 일시적으로 저장되는 공간
  • (데이터 영역에 담기는 값과는 달리) 잠깐 쓰다가 마는 값들이 저장되는 공간
  • 예시 : 매개 변수, 지역 변수
✅ 정적 할당 영역 : 코드 영역과 데이터 영역은 크기가 변하지 않는다. 그래서 코드 영역과 데이터 영역을 ‘크기가 고정된 영역’이라는 점에서 정적 할당 영역이라고도 부른다.
✅ 동적 할당 영역 : 힙 영역과 스택 영역은 프로세스 실행 과정에서 그 크기가 변할 수 있는 영역이다.
✅ 일반적으로 힙 영역은 메모리의 낮은 주소에서 높은 주소로 할당하고
스택 영역은 메모리의 높은 주소에서 낮은 주소로 할당하여 데이터가 쌓여도 할당되는 주소가 겹칠 일이 없게 한다.

힙 영역과 스택 영역의 메모리 주소가 겹치지 않게 한다.

10-2 프로세스 상태와 계층 구조

프로세스 상태

  • 대부분의 운영체제에서 사용하는 프로세스 상태 (차이가 있을 수 있음)
  1. 생성 상태 (new)
    • 이제 막 메모리에 적재되어 PCB를 할당 받은 상태
    • 준비가 완료되었다면 준비 상태로 변경한다.
  2. 준비 상태 (ready)
    • 당장이라도 CPU를 할당 받아 실행할 수 있지만 자신의 차례가 아니기에 기다리는 상태
    • 자신의 차례가 된다면 실행 상태로 변경한다. (=디스패치)
  3. 실행 상태 (running)
    • CPU를 할당 받아 실행 중인 상태
    • 할당된 시간을 모두 사용 시 (타이머 인터럽트 발생 시) 준비 상태로 되돌아감
    • 실행 도중 입출력장치를 사용하면 입출력 작업이 끝날 때까지 대기 상태로 변경됨 (입출력 인터럽트를 받을 때까지)
  4. 대기 상태 (blocked)
    • 프로세스가 실행 도중 입출력장치를 사용하는 경우
    • 입출력 작업은 CPU에 비해 느리기에 이 경우 대기 상태로 접어듬
    • 입출력 작업이 끝나면 (입출력 완료 인터럽트를 받으면) 준비 상태로 되돌아감
  5. 종료 상태 (terminated)
    • 프로세스가 종료된 상태
    • PCB, 프로세스의 메모리 영역 정리

프로세스 상태 다이어그램

아주 중요함 😱


프로세스 계층 구조

  • 프로스 실행 도중 (시스템 호출을 통해) 다른 프로세스 생성 가능
  • 새 프로세스를 생성한 프로세스 : 부모 프로세스
  • 부모 프로세스에 의해 생성된 프로세스 : 자식 프로세스
  • 부모 프로세스와 자식 프로세스는 별개의 프로세스이므로 각기 다른 PID를 가짐
  • 일부 운영체제에서는 자식 프로세스 PCB에 부모 프로세스 PID(PPID)를 명시하기도 한다.
  • 자식 프로세스는 또 다른 자식 프로세스를 낳을 수 있다. (반복) ➡️ 프로세스의 계층적인 구조 생성

최초의 프로세스로부터 계층적으로 구성된 프로세스 예시

 

✅ 데몬이나 서비스 또한 최초 프로세스의 자식 프로세스이다.


프로세스 생성 기법 (Windows 운영체제와는 큰 관련이 없다)

  • 부모 프로세스를 통해 생성된 자식 프로세스들은 복제와 옷 갈아입기를 통해 실행된다.
  • 부모 프로세스는 fork 시스템 호출을 통해 자신의 복사본을 자식 프로세스로 생성
  • 자식 프로세스는 exec 시스템 호출을 통해 자신의 메모리 공간을 다른 프로그램으로 교체

fork 시스템 호출

  • fork 시스템 호출을 통해 자신의 복사본을 자식 프로세스로써 생성한다.
  • 복사본( =자식 프로세스) 생성 (엄연히 다른 프로세스이기에 PID가 다름)
  • 부모 프로세스의 자원 상속


exec 시스템 호출

  • 메모리 공간을 새로운 프로그램으로 덮어쓰기
  • 코드/데이터 영역은 실행할 프로그램 내용으로 바뀌고 나머지 영역은 초기화

 

10-3 스레드

스레드

  • 스레드(thread)는 프로세스를 구성하는 실행 흐름의 단위
  • 하나의 프로세스는 하나 이상의 스레드를 가질 수 있다.
✅ 단일 스레드 프로세스 : 실행의 흐름 단위가 하나인 프로세스
✅ 멀티 스레드 프로세스 : 실행 흐름이 여러 개인 프로세스 ➡️ 프로세스를 이루는 여러 명령어를 동시 실행 가능


스레드의 구성 요소

  • 스레드ID, 프로그램 카운터를 비롯한 레지스터 값, 스택 등
  • 실행에 필요한 최소한의 정보를 가지고 있다.

  • 실행에 필요한 최소한의 정보를 가지고 있지만 프로세스의 자원을 공유한다.
  • 프로세스의 코드 영역과 데이터 영역을 스레드가 이용하기 때문

 

✅ 프로세스가 실행되는 프로그램이라면, 스레드는 프로세스를 구성하는 실행의 흐름 단위
➡️ 실제로 최근 많은 운영체제에서 CPU에 처리할 작업을 전달할 때 프로세스가 아닌 스레드 단위로 전달한다.


멀티 프로세스와 멀티 스레드

  • 동일한 작업을 수행하는 : 단일 스레드 프로세스 여러개 vs 하나의 프로세스를 여러 스레드로 실행

  • 둘 다 결과적으로 3번의 실행이 발생하지만 큰 차이가 있다.
  • 프로세스끼리는 기본적으로 자원을 공유하지 않음 vs 스레드끼리는 같은 프로세스 내의 자원을 공유함


멀티 프로세스의 경우

  • 프로세스를 fork 할 경우 코드/데이터/힙 영역 등 모든 자원이 복제되어 저장됨
  • 저장된 메모리 주소를 제외하면 모든 것이 동일한 프로세스 두 개가 통째로 메모리에 적재되는 형태
  • 중복되는 자원 ➡️ 자원의 낭비
  • 자원을 공유하지 않는다. ➡️ 남남처럼 독립적으로 실행된다. ➡️ 자원의 낭비
✅ 프로세스 간에도 자원을 주고 받을 수 있다. : 프로세스 간 통신 (IPC)
파일을 통한 프로세스 간 통신, 공유 메모리를 통한 프로세스 간 통신 등이 존재함


멀티 스레드의 경우

  • 스레드들은 각기 다른 스레드 ID, (별도의 실행을 위해 꼭 필요한) 프로그램 카운터 값을 포함한 레지스터 값, 스택을 가질 뿐 프로세스가 가지는 자원을 공유한다.
  • 자원을 공유한다. ➡️ 협력과 통신에 유리하다. ➡️ 공유되는 자원으로 문제가 될 수도 있다.

1️⃣1️⃣ CPU 스케줄링

11-1 CPU 스케줄링 개요

CPU 스케줄링

  • 운영체제가 프로세스들에게 공정하고 합리적으로 CPU 자원을 배분하는 것

가장 공정한 CPU 스케줄링?

  • CPU를 사용하고 싶어하는 프로세스들이 차례로 돌아가면서 사용
  • 빠르게 처리 되어야 하는 프로세스가 존재한다 (= 프로세스마다 우선순위가 다르다)
  • 입출력 작업이 많은 프로세스 (= 입출력 집중 프로세스)의 우선순위는 CPU 작업이 많은 프로세스 (= CPU 집중 프로세스)의 우선순위보다 높다.
  • 입출력 집중 프로세스는 대기 상태가 많기 때문에 먼저 처리하고 대기 상태일때 CPU 집중 프로세스를 처리하면 효율적이다.
✅ 입출력 집중 프로세스 : I/O bound process, CPU 집중 프로세스 : CPU bound process


프로세스 우선순위(priority)

  • PCB에 적힌 우선순위를 기준으로 먼저 처리할 프로세스를 결정한다.
  • 자연스럽게 우선순위가 높은 프로세스는 더 빨리, 더 자주 실행된다.


스케줄링 큐

  • 매번 모든 프로세스의 PCB를 검색해서 우선순위를 확인하는 것은 비효율적이다.
  • CPU 스케줄링 큐에 프로세스들을 줄 세워둔다.
  • 스케줄링에서의 큐는 반드시 FIFO(선입선출) 방식일 필요는 없다. (중간에 추가되고 바뀔 수도 있으니)
  • 같은 큐 내에서도 우선순위에 따라 처리 된다.


준비 큐

  • CPU를 이용하기 위해 기다리는 줄

대기 큐

  • 입출력장치를 이용하기 위해 기다리는 줄
  • 입출력장치별로 큐가 존재하여 같은 장치를 요구한 프로세스들을 같은 큐로 묶어서 대기

선점형 스케줄링 (preemptive scheduling)

  • 프로세스가 CPU를 비롯한 자원을 사용하고 있더라도 운영체제가 프로세스로부터 자원을 강제로 빼앗아 다른 프로세스에게 할당할 수 있는 스케줄링 방식
  • 장점 : 어느 하나의 프로세스가 자원 사용을 독점을 막고 프로세스들에 골고루 자원을 배분할 수 있다.
  • 단점 : 그만큼 문맥 교환 과정에서 오버헤드가 발생할 수 있다.

비선점형 스케줄링 (non-preemptive scheduling)

  • 하나의 프로세스가 자원을 사용하고 있다면 그 프로세스가 종료되거나 스스로 대기 상태에 접어들기 전까지 다른 프로세스가 끼어들 수 없는 스케줄링
  • 장점 : 문맥 교환에서 발생하는 오버헤드가 선점형 스케줄링보다 적다.
  • 단점 : 모든 프로세스가 골고루 자원을 이용하기 어렵다.

11-2 CPU 스케줄링 알고리즘

CPU 스케줄링 알고리즘은 다양하고 운영체제마다 다르다.

CPU 스케줄링의 종류 (일반적인 전공서 기준의 기본)

  1. 선입 선처리 스케줄링
  2. 최단 작업 우선 스케줄링
  3. 라운드 로빈 스케줄링
  4. 최소 잔여 시간 우선 스케줄링
  5. 우선순위 스케줄링
  6. 다단계 큐 스케줄링
  7. 다단계 피드백 큐 스케줄링


선입 선처리 스케줄링

  • FCFS (First Come First Served) 스케줄링
  • 단순히 준비 큐에 삽입된 순서대로 처리하는 비선점 스케줄링
  • 먼저 CPU를 요청한 프로세스부터 CPU 할당
  • 단점 : 프로세스들이 기다리는 시간이 매우 길어질 수 있다는 부작용 (=호위 효과)


최단 작업 우선 스케줄링

  • SJF (Shortest Job First) 스케줄링
  • 선입 선처리 스케줄링에서 호위 효과를 방지하는 스케줄링
  • CPU 사용이 긴 프로세스는 나중에 실행, CPU 사용 시간이 짧은 프로세스는 먼저 실행
  • CPU 사용 시간이 가장 짧은 프로세스부터 처리하는 스케줄링 방식
  • 선점형/비선점형으로 구현될 수 있고 기본적으론 비선점형으로 분류됨


라운드 로빈 스케줄링

  • RR (Round Robin) 스케줄링
  • 선입 선처리 스케줄링 + 타임 슬라이스 (time slice)
  • 타임 슬라이스 : 각 프로세스가 CPU를 사용할 수 있는 정해진 시간
  • 정해진 타임 슬라이스만큼의 시간 동안 돌아가며 CPU를 이용하는 선점형 스케줄링
    1. 큐에 삽입된 프로세스들은 순서대로 CPU를 이용하되 정해진 시간만큼만 이용한다.
    2. 정해진 시간을 모두 사용하였음에도 아직 프로세스가 완료되지 않았다면 다시 큐의 맨 뒤에 삽입 (문맥교환)
  • 타임 슬라이스의 크기가 중요하다. (너무 크면 선입 선처리 스케줄링과 다를 바가 없고, 너무 작으면 문맥 교환에 발생하는 비용이 커진다.)


최소 잔여 시간 우선 스케줄링

  • SRT (Shortest Remaining Time) 스케줄링
  • 최단 작업 우선 스케줄링 + 라운드 로빈 스케줄링
  • 최단 작업 우선 스케줄링 : 작업 시간이 짧은 프로세스부터 처리하는 스케줄링 알고리즘
  • 라운드 로빈 스케줄링 : 정해진 타임 슬라이스만큼 돌아가며 사용하는 스케줄링 알고리즘
  • 정해진 시간만큼 CPU를 이용하되, 다음으로 CPU를 사용할 프로세스는 남은 작업 시간이 가장 적은 프로세스로 선택한다.


우선순위 스케줄링

  • 프로세스들에 우선순위를 부여하고, 우선순위 높은 프로세스부터 실행
  • 우선순위가 같은 프로세스들은 선입 선처리로 스케줄링
  • 최단 작업 우선 스케줄링, 최소 잔여 시간 스케줄링은 넓은 의미에서 우선순위 스케줄링에 일종이다.
  • 우선순위 스케줄링의 근본적인 문제점, 기아(starvation) 현상
  • 우선순위 높은 프로세스만 주구장창 실행
  • 우선순위 낮은 프로세스는 (준비 큐에 먼저 삽입되었음에도 불구하고) 실행 연기
  • 기아현상을 방지하기 위한 기법 : 에이징(aging)
  • 오랫동안 대기한 프로세스의 우선순위를 점차 높이는 방식
  • 대기 중인 프로세스의 우선순위를 마치 나이 먹듯 점차 증가시키는 방법
  • 즉, 우선순위가 낮아도 언젠가는 우선순위가 높아진다.


다단계 큐 스케줄링

  • Multilevel queue 스케줄링
  • 우선순위 스케줄링의 발전된 형태
  • 우선순위별로 준비 큐를 여러 개 사용하는 스케줄링 방식
  • 우선순위가 가장 높은 큐에 있는 프로세스를 먼저 처리
  • 우선순위가 가장 높은 큐가 비어 있으면 그 다음 우선순위 큐에 있는 프로세스 처리
  • 다단계 큐 스케줄링에서는 기본적으로 큐 간의 이동이 불가하다.
  • 우선순위가 낮은 프로세스는 계속해서 실행이 연기 될 수 있다.
  • 준비 큐 간에 이동이 불가능하기 때문에 기아현상이 발생할 수 있다.
✅ 프로세스 유형별로 우선순위를 구분하여 실행하는 것이 편리해진다. ➡️ 준비 큐별로 스케줄링 방식을 다양하게 적용할 수 있다.


다단계 피드백 큐 스케줄링

  • Multilevel feedback queue 스케줄링
  • 다단계 큐 스케줄링의 발전된 형태
  • 큐 간의 이동이 가능한 다단계 큐 스케줄링
  • 자연스럽게 CPU 집중 프로세스의 우선순위가 상대적으로 낮아지고 입출력 집중 프로세스의 우선순위는 상대적으로 높아진다.
  • 타임슬라이스에서 CPU 작업이 끝나지 않으면(CPU 작업이 많으면 = CPU 집중 프로세스) 다음 우선순위 큐로 이동…
  • 다단계 피드백 큐 스케줄링에서도 에이징 기법을 적용할 수 있다.
  • 어떤 프로세스의 CPU 시간이 길면 우선순위가 낮아지고, 어떤 프로세스가 낮은 우선순위 큐에서 너무 오래 기다리면 우선순위를 높이는 방식
  • 가장 일반적인 CPU 스케줄링 방식으로 알려져있음

커리큘럼 🫠


📃 기본 미션1

p.185, 확인 문제 3번 ) 다음 설명을 읽고 SRAM에 대한 설명인지 DRAM에 대한 설명인지 쓰세요.

보기 : SRAM, DRAM

① 주로 캐시 메모리로 활용됩니다.

② 주로 주기억장치로 활용됩니다.

③ 대용량화하기 유리합니다.

④ 집적도가 상대적으로 낮습니다.

 

🖍 ) 

① = SRAM

② = DRAM

③ = DRAM

④ = SRAM

 

📃 기본 미션2

p.205, 확인 문제 1번 ) 다음 보기에 있는 저장 장치들로 저장 장치 계층 구조 도식도를 채우세요.

보기 : 메모리, 보조기억장치, 캐시 메모리, 레지스터

🖍 ) 

① = 레지스터

② = 캐시 메모리

③ = 메모리

④ = 보조기억장치

 

📃 선택 미션

RAID의 정의와 종류를 간단히 정리해보기

🖍 )

문서내 위치로 이동


Chapter 6️⃣

06-1 RAM의 특징과 종류

RAM

  • 실행할 프로그램의 명령어와 데이터가 저장됨

휘발성 저장 장치

  • 전원을 끄면 저장된 명령어와 데이터가 모두 날아가는 저장 장치
  • RAM이 대표적이다.
  • CPU가 ‘실행할 대상’을 저장한다.

비 휘발성 저장 장치

  • 전원이 꺼져도 저장된 내용이 유지되는 저장 장치
  • 하드 디스크, SSD, CD-ROM, USB 메모리 등이 있다.
  • CPU가 직접 접근하지 못한다.
  • 작업 결과물과 같은 ‘보관할 대상’을 저장한다.
✅ RAM 용량이 크다면 CPU가 실행하고자 하는 프로그램을 RAM에 많이 저장 할 수 있으며, 보조 기억장치로의 접근이 최소화 되어 시간을 절약할 수 있다.

 

DRAM (Dynamic RAM)

  • 저장된 데이터가 동적으로 사라지는 RAM
  • 데이터 소멸을 막기 위해 주기적으로 재활성화 해야한다.
  • 일반적으로 메모리로써 사용하는 RAM
  • 소비 전력이 비교적 낮고, 용량 대비 저렴, 집적도가 높다
✅ 집적도가 높다 : 더 작고 빽빽하게 만들 수 있다.

 

SRAM (Static RAM)

  • 저장된 데이터가 정적인 (사라지지 않는) RAM
  • 전원 공급이 멈추면 저장된 데이터가 날아가긴 한다.
  • DRAM보다 일반적으로 더 빠름
  • 일반적으로 캐시 메모리에서 사용되는 RAM
  • 상대적으로 소비전력이 높고, 가격이 높고, 집적도가 낮다
  • 대용량으로 설계할 필요는 없으나 빨라야 하는 장치에 사용한다.

 

  DRAM SRAM
재충전 필요함 필요 없음
속도 느림 빠름
가격 저렴함 비쌈
집적도 높음 낮음
소비 전력 적음 높음
사용 용도 주기억장치(RAM) 캐시 메모리

 

SDRAM (Synchronous DRAM)

  • 발전된 형태의 DRAM
  • 클럭 신호와 동기화된 DRAM
  • 클럭 신호와 동기화 되어있다는 의미는 CPU와 정보를 주고 받을 수 있다는 의미이다.

DDR SDRAM(Double Data Rate SDRAM)

  • 발전된 형태의 SDRAM
  • 최근 가장 대중적으로 사용하는 RAM
  • 대역폭을 넓혀 속도를 빠르게 만든 SDRAM
  • 비유적으로 대역폭은 데이터를 주고 받는 길의 너비

 

06-2 메모리의 주소 공간

CPU와 실행 중인 프로그램은 메모리 몇 번지에 무엇이 저장되어 있는지 다 알지 못한다.

메모리에 저장된 값들은 시시각각 변한다

 

물리 주소

  • 메모리 하드웨어가 사용하는 주소
  • 메모리 입장에서 바라본 주소
  • 말 그대로 정보가 실제로 저장된 하드웨어상의 주소

논리 주소

  • CPU와 실행 중인 프로그램이 사용하는 주소
  • CPU와 실행 중인 프로그램 입장에서 바라본 주소
  • 실행 중인 프로그램 각각에게 부여된 0번지부터 시작하는 주소
  • 새롭게 실행되는 프로그램은 새롭게 메모리에 적재
  • 실행이 끝난 프로그램은 메모리에서 삭제
  • 같은 프로그램을 실행하더라도 실행할 때마다 적재되는 주소는 달라짐

결국엔 논리 주소를 물리 주소로 변환해야 한다. → 실질적인 메모리 접근을 위해서

MMU (메모리 관리 장치)라는 하드웨어에 의해 변환

MMU는 논리 주소와 베이스 레지스터 값을 더하여 논리 주소를 물리 주소로 변환한다.

대충 말하면 찰떡같이 알아낸다!

 

 

✅ 베이스 레지스터 : 프로그램의 기준 주소, 프로그램의 시작 주소(물리 주소)
2주차 강의 중 레지스터 항목을 참고 (https://goming0925.tistory.com/16)

정리하면,

베이스 레지스터는 프로그램의 가장 작은 물리 주소, 프로그램의 첫 물리 주소를 저장한다.

논리 주소는 프로그램의 시작점으로부터 떨어진 거리이다.

 

메모리 보호 기법

  • 가정 : 본인 프로그램 논리 주소번지를 벗어나는 값의 데이터를 변경한다 ➡️ 타 프로그램의 데이터에 변화가 생긴다 ➡️ 으악☠️
  • 논리 주소 범위를 벗어나는 명령어 실행을 방지하고 실행 중인 프로그램이 다른 프로그램에 영향을 받지 않도록 보호할 방법이 필요 : 한계 레지스터
  • CPU는 메모리에 접근하지 전에 접근하고자 하는 논리 주소가 한계 레지스터보다 작은지를 항상 검사한다.
  • 실행 중인 프로그램의 독립적인 실행 공간을 확보
  • 하나의 프로그램이 다른 프로그램을 침범하지 못하게 보호

타 프로그램의 메모리 영역을 침범하는건 해킹? 🧑&zwj;💻

 

한계 레지스터

  • 프로그램의 영역을 침범할 수 있는 명령어의 실행을 막을때 사용
  • 베이스 레지스터가 실행 중인 프로그램의 가장 작은 물리 주소를 저장한다면, 한계 레지스터는 논리 주소의 최대 크기를 저장
  • 베이스 레지스터 값 ≤ 프로그램의 물리 주소 범위 < 베이스 레지스터 + 한계 레지스터 값

CPU가 접근하려는 논리 주소는 한계 레지스터가 저장한 값보다 커서는 안된다.

06-3 캐시 메모리

저장 장치의 일반적인 명제 (저장 장치 계층 구조의 개념)

  1. CPU와 가까운 저장 장치는 빠르고, 멀리 있는 저장 장치는 느리다.
  2. 속도가 빠른 저장 장치는 저장 용량이 작고, 가격이 비싸다.
  • 낮은 가격대의 대용량 저장 장치를 원한다면 느린 속도를 감수해야 하고, 빠른 속도의 저장 장치를 원한다면 작은 용량과 비싼 가격을 감수해야 한다.모든 것을 만족시키기엔 현실적으로 어렵다!

트라이포스!! 내 소원을 들어줘!! 🧝🗡️🏹🛡️

 

저장 장치의 계층 구조 (memory hierachy)

  • 일반적으로 컴퓨터는 다양한 저장 장치를 모두 사용한다.
  • 컴퓨터가 사용하는 저장 장치들을 ‘CPU에 얼마나 가까운지’를 기준으로 계층적으로 나타낼 수 있다. → 저장 장치 계층 구조

저장 장치에도 계층이 있다니...

 

캐시 메모리

  • CPU와 메모리 사이에 위치한, 레지스터보다 용량이 크고 메모리보다 빠른 SRAM 기반의 저장 장치
  • CPU의 연산 속도와 메모리의 접근 속도의 차이를 조금이나마 줄이기 위해 탄생
  • 매번 CPU와 메모리의 접근이 발생하면 시간이 오래 걸리니, 메모리에서 CPU가 사용할 일부 데이터를 미리 캐시 메모리로 가지고 와서 쓰자는 컨셉
  • 저장 장치의 계층 구조상으로는 레지스터와 메모리의 사이에 위치한다.
  • 캐시 메모리는 여러 개가 존재하며, CPU(코어)와 가까운 순서대로 계층을 구성한다.
  • 코어와 가장 가까운 캐시 메모리를 L1(level 1) 캐시, L2(level 2) 캐시, L3(level 3) 캐시 순서로 나열할 수 있다.
  • 용량 : L1 < L2 < L3
  • 속도 : L1 > L2 > L3
  • 가격 : L1 > L2 > L3

CPU 살때 캐시 메모리 보는 사람?

✅ 코어와 가장 가까운 L1 캐시는 조금이라도 접근 속도를 빠르게 만들기 위해 명령어만을 저장하는 L1I 과 데이터만을 저장하는 L1D 캐시로 분리하는 분리형 캐시(split cache)도 존재한다.
✅ 계층을 나누게 된 저장 장치의 특징이 중요하다 (속도, 용량, 가격의 변동)

 

참조 지역성의 원리

  • 캐시 메모리는 CPU가 자주 사용할 법한 내용을 예측해서 저장해야한다.
  • CPU가 사용할 법한 데이터를 예측하는 방법을 참조 지역성의 원리라고 한다.
  • CPU가 메모리에 접근할 때의 주된 경향을 바탕으로 만들어진 원리
    1. CPU는 최근에 접근했던 메모리 공간에 다시 접근하려는 경향이 있다.
    2. CPU는 접근한 메모리 공간 근처를 접근하려는 경향이 있다.

참조 지역성의 원리 1

  • 변수에 저장한 값을 다시 접근해서 사용하려는 형태

참조 지역성의 원리 2

  • 공간 지역성
  • 메모리 공간을 구획으로 나누어 만들어진 프로그램은 인접한 영역에서 관련 기능 및 데이터가 존재한다.

끼리끼리 모인다. 👥

 

캐시 히트

  • CPU가 캐시 메모리에 저장된 값을 활용할 경우, 즉 예측이 들어맞을 경우를 ‘캐시 히트’라고 표현한다.

캐시 미스

  • CPU가 캐시 메모리에 저장된 값을 활용하지 않는 경우(메모리에 접근해야 하는 경우), 즉 예측이 틀린 경우를 ‘캐시 미스’라고 표현한다.

캐시 적중률

  • 캐시 히트 횟수 / (캐시 히트 횟수 + 캐시 미스 횟수)
  • 캐시 적중률이 높을 수록 성능이 좋다 → CPU와 메모리와의 접근 횟수를 줄일 수 있다.
  • 최근 CPU의 캐시 적중률은 80퍼센트에 육박한다. (무려!!)

Chapter 7️⃣

07-1 다양한 보조기억장치

하드 디스크

  • 자기적인 방식으로 데이터를 저장하는 보조기억장치
  • 자기 디스크의 일종
  • 실질적으로 데이터가 저장되는 플래터 : 자기 물질로 덮여 있어 N극과 S극의 정보를 저장 (0과 1의 역할)
  • 플래터를 회전시키는 스핀들

동작할때 흔들면 난리나는 이유 (물리적 충격에 약한 이유)

✅ 일반적으로 플래터 양면을 모두 사용한다.
✅ RPM(Revolution Per Minute) : 분당 회전수, 스핀들이 플래터를 돌리는 속도 단위
  • 플래터를 대상으로 데이터를 읽고 쓰는 헤드, 플래터 위에서 미세하게 떠 있는 채로 데이터를 읽고 쓴다.
  • 헤드를 원하는 위치로 이동시키는 디스크 암, 일반적으로 모든 헤드가 디스크 암에 부착되어 함께 이동한다.

플래터의 면마다 헤드가 존재한다.

하드 디스크 - 저장 단위

  • 기본적으로 트랙(track)과 섹터(sector) 단위로 데이터를 저장
  • 플래터를 이루고 있는 동심원을 트랙
  • 섹터는 트랙의 일부로 플래터 위의 부채꼴 모양의 영역을 의미
  • 섹터의 크기는 512 바이트 ~ 4096 바이트
  • 하나 이상의 섹터를 묶어 블록(block)이라고 표현하기도 한다.
  • 실린더 : 여러 겹의 플래터 상에서 같은 트랙이 위치한 곳을 모아 연결한 논리적인 단위
  • 연속된 정보 실린더에 기록된다. : 헤드를 따로 움직이지 않고 한번에 읽을 수 있기 때문에 (플래터 사이사이에 많기 때문에)

하드 디스크 - 데이터 접근 과정

  • 하드 디스크가 저장된 데이터에 접근하는 시간을 크게 3개로 나눌 수 있다.
  1. 탐색 시간 (seek time)
  2. 회전 지연 (rotational latency)
  3. 전송 시간 (transfer time)
  • 하드 디스크의 작업 성능은 많이 향상되었지만 컴퓨터 작업내에선 정말 많은 시간이 소요된다.

 

탐색 시간 (seek time)

  • 접근하려는 데이터가 저장된 트랙까지 헤드를 이동시키는 시간

 

회전 지연 (rotational latency)

  • 헤드가 있는 곳으로 플래터를 회전시키는 시간

 

전송 시간 (transfer time)

  • 하드 디스크와 컴퓨터 간에 데이터를 전송하는 시간

탐색, 회전, 전송!!! 💿

 

 

플래시 메모리

  • 전기적으로 데이터를 읽고 쓰는 반도체 기반 저장 장치
  • 플래시 메모리는 범용성이 넓어서 보조기억장치에만 쓰이지 않고 다양하게 쓰인다.
✅ 플래시 메모리는 NAND 연산을 수행하는 회로 기반으로 만들어진 NAND 플래시 메모리와 NOR 연산 회로 기반으로 만들어진 NOR 플래시 메모리가 있다. 대용량 저장 장치로 많이 사용되는건 NAND 플래시 메모리이다.

 

셀 (cell)

  • 플래시 메모리에서 데이터를 저장하는 가장 작은 단위
  • 셀이 모여서 MB, GB, TB 저장 장치가 된다.
  • 한 셀에 1 비트를 저장할 수 있는 플래시 메모리 : SLC
  • 한 셀에 2 비트를 저장할 수 있는 플래시 메모리 : MLC
  • 한 셀에 3 비트를 저장할 수 있는 플래시 메모리 : TLC
  • 한 셀에 4 비트를 저장할 수 있는 플래시 메모리 : QLC
  • 셀에 저장할 수 있는 비트 수에 따라 플래시 메모리의 수명, 성능, 가격에 영향을 미친다.

SLC

  • 한 셀로 두 개의 정보를 표현할 수 있다.
  • 비트의 빠른 입출력
  • 긴 수명
  • 용량 대비 가격이 높다

MLC

  • 한 셀에 네 개의 정보를 표현할 수 있다. (대용량화하기 유리하다.)
  • SLC 보다 느린 입출력
  • SLC 보다 짧은 수명
  • SLC 보다 저렴하다.
  • 시중에서 많이 사용 (MLC, TLC, QLC)

TLC

  • 한 셀에 여덟 개의 정보를 표현할 수 있다. (대용량화하기 유리하다.)
  • MLC 보다 느린 입출력
  • MLC 보다 짧은 수명
  • MLC 보다 저렴하다.
  • 시중에서 많이 사용 (MLC, TLC, QLC)

플래시 메모리 - 저장 단위

  • 셀들이 모여서 페이지(page)
  • 페이지들이 모여서 블록(block)
  • 블록이 모여서 플레인(plane)
  • 플레인이 모여서 다이(die)
  • 읽기와 쓰기는 페이지 단위로 이루어진다.
  • 삭제는 (페이지보다 큰) 블록 단위로 이루어진다.

중요한건 읽기/쓰기 와 삭제의 단위가 다르다는 점?!

페이지의 상태

  • Free 상태 : 어떠한 데이터도 저장하고 있지 않아 새로운 데이터를 저장할 수 있는 상태
  • Valid 상태 : 이미 유효한 데이터를 저장하고 있는 상태
  • Invalid 상태 : 유효하지 않은 데이터(쓰레기값)를 저장하고 있는 상태
✅ 플래시 메모리는 하드 디스크와 달리 덮어쓰기가 불가능하다. (invalid 상태가 존재한다.)

 

가비지 컬렉션 (garbage collection)

  • 플래시 메모리 사용 중에 invalid 페이지가 용량을 차지하므로 공간을 정리하기 위한 기능 (공간을 관리하는 기능)
  1. 유효한 페이지들만을 새로운 블록으로 복사
  2. 기존의 블록을 삭제

여유 공간이 없으면요...? 🙀

 

07-2 RAID의 정의와 종류

RAID (Redundant Array of Independent Disks)

  • 하드 디스크와 SSD로 사용하는 기술
  • 데이터의 안전성 혹은 높은 성능을 위해 여러 물리적 보조기억장치를 마치 하나의 논리적 보조기억장치처럼 사용하는 기술

RAID 레벨

  • RAID를 구성하는 기술
  • RAID 0, RAID 1, RAID 2, RAID 3, RAID 4, RAID 5, RAID 6
  • 그로부터 파생된 RAID 10, RAID 50 등이 있다.
  • RAID 0, RAID 1, RAID 4, RAID 5, RAID 6 이 대중적으로 사용된다.

RAID 0

  • 데이터를 단순히 나누어 저장하는 구성 방식
  • 각 보조기억장치는 번갈아 가며 데이터를 저장한다.
  • 저장되는 데이터가 보조기억장치의 갯수만큼 나뉘어 저장된다.
  • 장점 : 입출력 속도의 향상 (여러개의 보조기억장치로부터 동시에 입출력을 발생시킨다.)
  • 단점 : 저장된 정보가 안전하지 않음 (하나의 장치만 고장나도 데이터를 사용할 수 없다.)

✅ 스트라입 (stripe) : 마치 줄무늬처럼 분산되어 저장된 데이터
✅ 스트라이핑 (striping) : 분산하여 저장하는 것

 

RAID1

  • 미러링 (mirroring) : 복사본을 만드는 방식
  • 데이터를 쓸 때 원본과 복사본 두 군데에 씀 (느린 쓰기 속도)

  • 장점 : 백업과 복구가 쉽다. (데이터가 안전하다.)
  • 단점 : 하드 디스크 개수가 한정되었을 때 사용 가능한 용량이 적어짐
  • 복사본이 만들어지는 용량만큼 사용 불가 ➡️ 많은 양의 하드 디스크가 필요 ➡️ 비용 증가

RAID 4

  • (RAID 1처럼 완전한 복사본을 만드는 대신) 오류를 검출하고 복구하기 위한 정보를 저장
  • 패리티 비트 : 오류를 검출하고 복구하기 위한 정보
  • 패리티를 저장한 장치를 이용해 다른 장치들의 오류를 검출하고, 오류가 있다면 복구할 수 있다.

✅ 원래 패리티 비트는 오류 검출만 가능할 뿐 오류 복구는 불가능하다. RAID에서 사용하는 패리티는 오류 검출 뿐만 아니라 복구도 가능하다.
  • 단점 : 패리티 디스크의 병목 현상이 발생 할 수 있다. (디스크에 저장될때 마다 패리티 디스크에 저장을 하기 때문에…)

RAID 5

  • 패리티 정보를 분산하여 저장하는 방식

RAID 6

  • 두 종류의 패리티 (오류를 검출하고 복구할 수 있는 수단)을 저장한다.
  • RAID 5 보다 안전하지만 쓰기는 RAID 5보다 느리다.

정리

  • 각 RAID 레벨마다 장단점이 있음
  • 어떤 상황에서 무엇을 최우선으로 원하는지에 따라 최적의 RAID 레벨은 달라질 수 있음
  • 각 RAID 레벨의 대략적인 구성과 특징을 아는 것이 중요하다.

8️⃣ 입출력장치

08-1 장치 컨트롤러와 장치 드라이버

입출력장치가 CPU, 메모리보다 다루기 까다로운 이유

  1. 입출력장치는 종류가 너무나도 많다.
    1. 장치가 다양하면 장치마다 속도, 데이터 전송 형식 등도 다양하다.
    2. 다양한 입출력장치와 정보를 주고받는 방식을 규격화하기 어렵다.
  2. 일반적으로 CPU와 메모리의 데이터 전송률은 높지만 입출력장치의 데이터 전송률은 낮다.
    • 전송률 (transfer rate) : 데이터를 얼마나 빨리 교환할 수 있는지를 나타내는 지표

장치 컨트롤러

  • 위와 같은 어려움을 해결하기 위해 입출력장치는 장치 컨트롤러를 통해 컴퓨터와 연결된다.
  • 입출력 제어기 (I/O controller), 입출력 모듈 (I/O module)이라고 불리기도 한다.

장치 컨트롤러의 역할

  • CPU와 입출력장치 간의 통신중개 : 까다로운 이유 1번을 해결
  • 오류 검출 : 장치의 오류 상태를 확인
  • 데이터 버퍼링 : 데이터를 모았다가 조금씩 내보내거나, 한 번에 내보내서 전송률을 맞춰준다. (까다로운 이유 2번)
✅ 버퍼링 : 전송률이 높은 장치와 낮은 장치 사이에 주고받는 데이터를 버퍼라는 임시 저장 공간에 저장하여 전송률을 비슷하게 맞추는 방법

 

장치 컨트롤러의 구조

  • 입출력버스 (시스템버스)에 연결되어 정보를 주고 받게 된다.
  • 주고 받는 정보는 크게 3개의 레지스터에 저장된다.
  • 데이터 레지스터, 상태 레지스터, 제어 레지스터

상태/제어 레지스터로 묶기도 한다

장치 컨트롤러 - 데이터 레지스터

  • CPU와 입출력장치 사이에 주고받을 데이터가 담기는 레지스터 (버퍼)
  • 최근엔 데이터 양이 많아짐에 따라 RAM을 사용하기도 한다.

장치 컨트롤러 - 상태 레지스터

  • 상태 정보 저장
  • 입출력장치가 입출력 작업을 할 준비가 되었는지 상태를 저장
  • 입출력 작업이 완료되었는지 상태를 저장
  • 입출력장치에 오류는 없는지 등의 상태 정보를 저장한다.

장치 컨트롤러 - 제어 레지스터

  • 입출력장치가 수행할 내용에 대한 제어 정보

장치 드라이버

  • 장치 컨트롤러의 동작을 감지하고 제어하는 프로그램
  • 장치 컨트롤러는 입출력장치를 연결하기 위한 하드웨어적인 통로
  • 장치 드라이버는 입출력장치를 연결하기 위한 소프트웨어적인 통로
  • 컴퓨터(운영체제)가 연결된 장치의 드라이버를 인식하고 실행할 수 있어야 컴퓨터 내부와 정보를 주고 받을 수 있음

 

08-2 다양한 입출력 방법

입출력 방식

  1. 프로그램 입출력
  2. 인터럽트 기반 입출력
  3. DMA 입출력

프로그램 입출력

  • 프로그램 속 명령어로 입출력장치를 제어하는 방법
  • 입출력 명령어로써 장치 컨트롤러와 상호작용
  • CPU가 장치 컨트롤러의 레지스터 값을 읽고 씀으로써 이루어진다.
  • CPU 내부에 있는 레지스터들과 달리 여러 장치 컨트롤러 속의 레지스터들을 모두 알고 있을 수 없다. (메모리 맵 입출력, 고립형 입출력)

메모리 맵 입출력 방식

  • 메모리에 접근하기 위한 주소 공간과 입출력장치에 접근하기 위한 주소 공간을 하나의 주소 공간으로 간주하는 방법
  • 주어진 메모리내에 주소공간을 ‘메모리를 위한 주소 공간’, ‘입출력장치를 위한 주소 공간’으로 나누어서 관리한다.
  • 메모리 접근 명령어 == 입출력장치 접근 명령어

고립형 입출력 방식

  • 메모리를 위한 주소 공간과 입출력 장치를 위한 주소 공간을 분리하는 방법
  • 주어진 메모리내에 모든 공간을 메모리를 위한 공간이나 입출력장치를 위한 주소 공간으로 쓸 수 있다.
  • (입출력 읽기/쓰기 선을 활성화 시키는) 입출력 전용 명령어를 사용한다.
메모리 맵 입출력 고립형 입출력
메모리와 입출력장치는 같은 주소 공간 사용 메모리와 입출력장치는 분리된 주소 공간 사용
메모리 주소 공간이 축소됨 메모리 주소 공간이 축소되지 않음
메모리와 입출력장치에 같은 명령어 사용 가능 입출력 전용 명령어 사용

인터럽트 기반 입출력

  • 하드웨어 인터럽트는 장치 컨트롤러에 의해 발생
  • 인터럽트 발생전까지 CPU가 다른 작업을 수행할 수 있다 ➡️ 효율적인 방식
✅ 폴링(polling) : 입출력장치의 상태와 처리할 데이터가 있는지를 주기적으로 확인하는 방식, 인터럽트 보다 CPU의 부담이 더 크다.

 

동시다발적인 인터럽트

  • 입출력장치가 많을 때 동시다발적인 인터럽트 요청이 발생한다.
  • 플래그 레지스터 속 인터럽트 비트를 비활성화한채 요청을 전부 순차적으로 해결할 순 없다. ➡️ NMI
  • 우선순위를 반영해서 다중 인터럽트를 처리해야한다.
✅ NMI (Non-Maskable Interrupt) : 중요도가 높아서 비활성화로 무시할 수 없는 인터럽트

 

프로그래머블 인터럽트 컨트롤러(PIC, Programmable Interrupt Controller)

  • 우선순위를 반영하여 다중 인터럽트를 처리하는 하드웨어
  1. 여러 장치 컨트롤러에 연결
  2. 장치 컨트롤러의 하드웨어 인터럽트의 우선순위를 판단한다.
  3. CPU에게 지금 처리해야 하는 인터럽트가 무엇인지 판단하여 알려준다.
  • NMI 우선순위까지 판단하지는 않음
  • PIC는 여러개를 사용하여 두 개 이상의 계층적으로 구성한다.

✅ 프로그램 입출력, 인터럽트 기반 입출력의 공통점은 입출력장치와 메모리 간의 데이터 이동은 CPU가 주도하고, 이동하는 데이터도 반드시 CPU를 거친다.

 

DMA 입출력 (Direct Memory Access)

  • 입출력장치와 메모리가 CPU를 거치지 않고도 상호작용할 수 있는 입출력 방식

  • DMA 컨트롤러라는 하드웨어가 필요하다.
  • CPU는 시간을 효율적으로 사용하면서 입출력 장치와 상호작용할 수 있다. (다른 작업에 집중할 수 있다.)

DMA 입출력 과정

  1. CPU는 DMA 컨트롤러에 입출력 작업을 명령
  2. DMA 컨트롤러는 CPU 대신 장치 컨트롤러와 상호작용하며 입출력 작업을 수행 (DMA 컨트롤러는 필요한 경우 메모리에 직접 접근한다.)
  3. 입출력 작업이 끝나면 DMA 컨트롤러는 인터럽트를 통해 CPU에 작업이 끝났음을 알림
  • DMA 입출력 과정에서 시스템 버스를 이용 ➡️ 시스템 버스는 공용 자원이기에 동시 사용이 불가능
  • CPU가 시스템 버스를 이용하지 않을 때마다 조금씩 시스템 버스를 이용하거나
  • CPU가 일시적으로 시스템 버스를 이용하지 않도록 허락을 구하고 시스템 버스를 이용한다.
✅ 사이클 스틸링 (cycle stealing) : CPU 입장에선 시스템 버스에 접근하는 주기를 도둑맞은 기분이 들기에, DMA의 시스템 버스 이용을 사이클 스틸링이라고 부르기도 한다.

 

입출력 버스

  • DMA가 시스템 버스를 불필요하게 점거하는 문제를 해결하기 위해 입출력 버스라는 별도의 버스를 이용한다.
  • PCI 버스, PCI express (PCIe) 버스와 입출력 장치를 연결짓는 슬롯
  • 슬롯 ➡️ 입출력 버스 ➡️ 시스템 버스

✅ 최근엔 DMA가 더욱 발전해서 입출력 전용 CPU가 만들어지기도 함 ➡️ 입출력 프로세서 혹은 입출력 채널

 

커리큘럼 🫠


📃 기본 미션1

p.125, 확인 문제 2번 ) 설명에 맞는 레지스터를 보기에서 찾아 빈칸을 채워 보세요.

보기 : 프로그램 카운터, 명령어 레지스터, 플래그 레지스터, 범용 레지스터

(①) : 연산 결과 혹은 CPU 상태에 대한 부가 정보를 저장하는 레지스터

(②) : 메모리에서 가져올 명령어의 주소를 저장하는 레지스터

(③) : 데이터와 주소를 모두 저장할 수 있는 레지스터

(④) : 해석할 명령어를 저장하는 레지스터

 

🖍 ) 

① = 플래그 레지스터

② = 프로그램 카운터

③ = 범용 레지스터

④ = 명령어 레지스터

 

📃 기본 미션2

p.155, 확인 문제 4번 ) 다음 그림은 멀티코어 CPU를 간략하게 도식화한 그림입니다. 빈칸에 알맞은 용어를 써 넣으세요.

🖍 ) 코어

현대적인 관점에서 ALU, 제어 장치, 레지스터세트를 가지는 '명령어를 실행하는 부품'은 코어로 지칭하며, 코어를 여러개 가지는 멀티코어 CPU로 CPU의 작업처리 속도를 증대시켰다.

 

📃 선택 미션

코어와 스레드, 멀티 코어와 멀티 스레드의 개념 정리하기

코어(core)?
현대적인 관점에서 CPU내에 '명령어를 실행하는 부품'이라는 용어로 사용되고 있는 부품 단위

전통적인 관점의 CPU와 현대적인 관점의 CPU

멀티코어(multi core)?
여러 개의 코어를 포함하고 있는 CPU
코어를 증가함에 따라 비례적으로 CPU의 연산 속도가 증가하는가? ➡️ 그건 아니다.
코어마다 처리할 명령어를 적절하게 분배하는 것에 따라 멀티코어의 연산 속도가 크게 달라진다.
스레드(thread)?
사전적 의미로 '실행 흐름의 단위'이다.
하드웨어적으로는 '하나의 코어가 동시에 처리하는 명령어 단위'를 뜻한다.
소프트웨어적으로는 '하나의 프로그램에서 독립적으로 실행되는 단위'를 뜻한다.

분야별로 사용되는 용례가 다르기 때문에 스레드를 두가지의 종류로 구분지어 기억해야한다.

멀티스레드(multi thread)?
하드웨어적으로는 CPU의 코어에 여러개의 스레드를 포함하여 여러 명령어를 동시에 처리할 수 있는 스레드
소프트웨어적으로는 하나의 프로세스 내에서 둘 이상의 스레드가 동시에 작업을 수행하는 것
멀티 스레드(ex. n스레드)의 작업 수행시 메모리 입장에선 작업 흐름이 동시에 n개 존재할 수 있다.
메모리의 입장에선 하나의 명령어를 처리하는 CPU가 n개 있는 것처럼 보인다.
그러므로 멀티스레드는 논리 프로세서(logical processor)를 여러개 가지는 것과 동일하다.

Chapter 4️⃣

04-1 ALU와 제어장치

ALU는 계산하는 장치, 제어장치는 제어 신호를 발생시키고 명령어를 해석하는 장치

CPU의 구조

 

 

ALU

  • ALU는 피연산자와 수행할 연산을 받아 계산을 수행한다.
  • 레지스터로부터 피연산자를 받아들인다.
  • 제어장치로부터 제어신호(산술 연산, 논리 연산)을 받아들인다.
  • 결괏값을 레지스터에 저장하는 이유는 메모리에 접근하는 속도보다 훨씬 빠르기 때문

ALU가 받는 신호와 내보내는 신호

 

플래그

  • ALU는 연산 결과에 대한 부가 정보로 플래그를 플래그 레지스터로 내보낸다.
  • 계산 결과에 대한 정보 (음수) 를 알리는 추가 정보를 담기도 한다.
  • 연산 결과가 연산 결과를 담을 레지스터보다 큰 상황인 오버플로우(overflow)를 알리기도 한다.
플래그 종류 의미 사용 예시
부호 플래그 연산한 결과의 부호를 나타낸다. 부호 플래그가 1일 경우 계산 결과는 음수, 0일경우 계산 결과는 양수를 의미한다.
제로 플래그 연산 결과가 0인지 여부를 나타낸다. 제로 플래그가 1일 경우 연산 결과는 0, 0일 경우 연산 결과는 0이 아님을 나타낸다.
캐리 플래그 연산 결과 올림수나 빌림수가 발생했는지를 나타낸다. 캐리 플래그가 1일 경우 올림수나 빌림수가 발생했음을 의미하고 0일 경우 발생하지 않았음을 의미한다.
오버플로우 플래그 오버플로우가 발생했는지를 나타낸다. 오버플로우 플래그가 1일 경우 오버플로우가 발생했음을 의미하고, 0일 경우 발생하지 않았음을 의미한다.
인터럽트 플래그 인터럽트가 가능한지를 나타낸다. 인터럽트 플래그가 1일 경우 인터럽트가 가능함을 의미하고, 0일 경우 인터럽트가 불가능함을 의미한다.
슈퍼바이저 플래그 커널 모드로 실행 중인지, 사용자 모드로 실행 중인지를 나타낸다. 슈퍼바이저 플래그가 1일 경우 커널 모드로 실행 중임을 의미하고, 0일 경우 사용자 모드로 실행 중임을 의미한다.

 

플래그 레지스터

  • 플래그 종류에 따른 정보를 저장하는 플래그 레지스터

플래그 정보들을 저장하는 플래그 레지스터

 

제어장치

  • 제어 신호를 내보내고, 명령어를 해석하는 부품
  • 제어 신호는 컴퓨터 부품들을 관리하고 작동시키기 위한 일종의 전기 신호
  • 제어 장치가 받아들이는 정보
    1. 제어장치는 클럭 신호를 받아들인다.
    2. 제어장치는 ‘해석해야 할 명령어’를 받아들인다.
    3. 제어장치는 플래그 레지스터 속 플래그 값을 받아들인다.
    4. 제어장치는 시스템 버스, 그 중에서 제어 버스로 전달된 제어 신호를 받아들인다. (입출력 장치를 비롯한 주변 장치의 제어 신호)
  • 제어 장치가 내보내는 정보
    1. CPU 외부에 전달하는 제어 신호 (레지스터나 ALU로 보내는 정보)
    2. CPU 내부에 전달하는 제어 신호 (메모리 혹은 입출력장치)

제어장치가 받아들이는 정보와 내보내는 정보

 

 

클럭 (clock)

  • 컴퓨터의 모든 부품을 일사불란하게 움직일 수 있게 하는 시간 단위

단위 시간당 클럭이 많이 발생하면 클럭 주기가 높다 😉

 

04-2 레지스터

레지스터

  • CPU 내부의 작은 임시저장장치
  • 프로그램 속 명령어 & 데이터는 실행 전후로 레지스터에 저장
  • CPU 내부에는 다양한 레지스터들이 있고 각기 역할이 다르다.

CPU내부에 존재하는 다양한 레지스터들

 

프로그램 카운터

  • 메모리에서 가져올 명령어의 주소를 저장한다.
  • 메모리에서 읽어 들일 명령어의 주소를 저장한다.
  • Instruction Pointer(명령어 포인터) 라고 부르는 CPU도 있음

명령어 레지스터

  • 해석할 명령어 (방금 메모리에서 읽어들인 명령어)를 저장한다.

메모리 주소 레지스터

  • 메모리의 주소를 저장한다.
  • CPU가 읽어 들이고자 하는 주소를 주소 버스로 보낼 때 거치는 레지스터

메모리 버퍼 레지스터

  • 메모리와 주고받을 값 (데이터와 명령어)를 저장한다.
  • CPU가 정보를 데이터 버스로 주고받을 때 거치는 레지스터
  • 메모리 데이터 레지스터 (MDR : Memory Data Register)라고도 부른다.

플래그 레지스터

  • 연산 결과 또는 CPU 상태에 대한 부가적인 정보를 저장한다.

범용 레지스터

  • 다양하고 일반적인 상황에서 자유롭게 사용한다.
  • 보통 여러개 존재한다.
  • 주소나 명령어 범용적으로 사용한다.

스택 포인터

  • 주소 지정에 사용한다.
  • 스택의 꼭대기 (TOS)를 가리키는 레지스터 : 스택이 어디까지 차 있는지에 대한 표시
  • 스택 영역
    • 메모리 안에 스택처럼 사용할 영역이 정해져 있다.
    • 다른 주소 공간과는 다르게 스택처럼 사용하기로 암묵적으로 약속된 영역이다.

스택 포인터에 TOS 주소가 저장되어있다.

베이스 레지스터

  • 주소 지정에 사용한다.
  • 변위 주소 지정 방식에서 사용된다.

레지스터에 저장된 값을 오퍼랜드 값과 합쳐서 메모리의 유효 주소로 활용한다!

변위 주소 지정 방식

  • 오퍼랜드 필드의 값(변위)과 특정 레지스터의 값을 더하여 유효 주소를 얻는 방식
  • 일반적으로 프로그램 카운터나 베이스 레지스터에 저장된 값을 오퍼랜드의 주소값과 더한 주소를 유효주소로 사용한다.
  • 프로그램 카운터를 활용하면 상대 주소 지정 방식
  • 베이스 레지스터를 활용하면 베이스 레지스터 주소 지정 방식

변위 주소 지정방식의 명령어 구조

상대 주소 지정 방식

  • 오퍼랜드 필드의 값(변위)과 프로그램 카운터의 값을 더하여 유효 주소를 얻는 방식

실행할 명령어의 주소가 담긴 프로그램 카운터로부터 오퍼랜드 값 만큼 이동한 곳에 있는 명령어를 수행한다.

베이스 레지스터 주소 지정 방식

  • 오퍼랜드 필드의 값(변위)과 베이스 레지스터의 값을 더하여 유효 주소를 얻는 방식

베이스 레지스터에 담긴 값을 기준으로 삼아 오퍼랜드의 값과 합쳐서 유효주소로 사용한다.

 

04-3 명령어 사이클과 인터럽트

명령어 사이클

  • CPU가 하나의 명령어를 처리하는 과정의 정형화된 흐름
  • 프로그램 속 각각의 명령어들은 명령어 사이클이 반복되며 일반적으로 인출 사이클과 실행 사이클을 반복하며 실행된다.
  • 인출 사이클
    • 메모리에 있는 명령어를 CPU로 가지고 오는 단계
  • 실행 사이클
    • CPU로 가져온 명령어를 실행하는 단계

✅ CPU로 명령어를 가지고 와도 바로 실행이 불가능한 경우도 있다. (간접 주소 지정방식) ➡️ 메모리 접근이 더 필요한 경우 간접 사이클이 추가되기도 한다.

명령어 사이클의 개요 (인터럽트를 추가하면 이것과는 달라진다.)

 

인터럽트

  • CPU의 정상적인 작업을 방해하는 신호
  • CPU가 꼭 주목해야할때, 얼른 처리해야할 다른 작업이 생겼을 때 발생
  • 명령어 사이클에 개입해서 작업을 중단시킨다.
  • 크게 동기 인터럽트(예외)와 비동기 인터럽트(하드웨어 인터럽트)가 존재한다.

동기 인터럽트

  • CPU가 예기치 못한 상황을 접했을 때 발생
  • 실행하는 프로그래밍상의 오류와 같은 예외적인 상황에서 발생하는 인터럽트로 예외(Exception)라고 부름

동기 인터럽트에 존재하는 4개지 종류

비동기 인터럽트

  • 주료 입출력장치에 의해 발생
  • 알림과 같은 역할
  • 입출력 작업 도중에도 효율적으로 명령어를 처리하기 위해 사용한다.
    • 입출력장치는 CPU에 비해 느리다.
    • 인터럽트가 없다면 CPU는 프린트 완료 여부를 확인하기 위해서 주기적으로 확인해야 함
    • 인터럽트가 있다면 입출력 작업 동안 CPU는 다른 일을 할 수 있다.

하드웨어 인터럽트의 처리 순서

✅ 인터럽트의 종류를 막론하고 인터럽트 처리 순서는 대동소이하다.

  1. 입출력장치는 CPU에 인터럽트 요청 신호를 보낸다.
  2. CPU는 실행 사이클이 끝나고 명령어를 인출하기 전 항상 인터럽트 여부를 확인한다.
  3. CPU는 인터럽트 요청을 확인하고 인터럽트 플래그를 통해 현재 인터럽트를 받아들일 수 있는지 여부를 확인한다.
  4. 인터럽트를 받아들일 수 있다면 CPU는 지금까지의 작업을 백업한다.
  5. CPU는 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴을 실행한다.
  6. 인터럽트 서비스 루틴 실행이 끝나면, 4에서 백업한 작업을 복구하여 실행을 재개한다.

인터럽트 요청 신호

  • 인터럽트 요청 주체 (ex. 입출력장치)가 CPU에게 보내는 요청 신호
  • CPU가 인터럽트 요청을 받아들이려면 플래그 레지스터의 인터럽트 플래그가 활성화 되어있어야 한다.

플래그 레지스터에 있는 인터럽트 플래그가 1일때 인터럽트 요청을 받아들인다.

  • 모든 인터럽트를 인터럽트 플래그로 막을 수 있는 건 아니다. ➡️ 막을 수 없는 인터럽트(non maskable interrupt) 존재

인터럽트 플래그 비활성에도 발생하는 인터럽트가 있다! 😱

인터럽트 서비스 루틴

  • CPU가 인터럽트를 받아들이기로 했다면 인터럽트 서비스 루틴을 실행한다.
  • 인터럽트가 발생했을 때 해당 인터럽트를 어떻게 처리하는지 작성된 프로그램
  • 인터럽트 서비스 루틴도 프로그램이기 때문에 메모리에 저장된다.

인터럽트 벡터

  • 인터럽트를 보낼 수 있는 주체가 여러 개 ➡️ 각각의 인터럽트를 구분하기 위한 정보
  • 인터럽트 벡터는 인터럽트 서비스 루틴을 식별하기 위한 정보
  • 인터럽트 벡터를 참조하여 인터럽트 서비스 루틴의 시작주소를 알아내고 실행한다.
CPU가 인터럽트를 처리한다 == 인터럽트 서비스 루틴을 실행하고, 본래 수행하던 작업으로 다시 되돌아온다 (+ 그리고 인터럽트의 시작 주소는 인터럽트 벡터를 통해 알 수 있다.)
인터럽트 서비스 루틴 실행 전의 CPU 수행 작업의 내역을 메모리 스택에 저장하고 인터럽트 서비스 루틴 종료 후 스택에 저장해 둔 값으로 작업을 재개한다.

인터럽트 사이클을 추가한 명령어 사이클


Chapter 5️⃣

05-1 빠른 CPU를 위한 설계 기법

앞선 내용 상기

  1. 컴퓨터 부품들은 ‘클럭 신호’에 맞춰 일사불란하게 움직인다.
  2. CPU는 ‘명령어 사이클’이라는 정해진 흐름에 맞춰 명령어들을 실행한다.

🤔 : 그럼 클럭 신호가 빠르게 반복되면 빠르고 많이 움직이는거 아니야?

✅ 일반적으로 옳다. 그렇기 때문에 CPU의 속도 단위로 간주되기도 한다.

 

클럭 속도

  • 헤르츠(Hz) 단위로 측정
  • 1 헤르츠는 1초에 클럭이 반복되는 횟수
  • 클럭이 1초에 한번 반복되면 1Hz, 1초에 100번 반복되면 100Hz
  • CPU 속도를 높이기 위해 클럭 속도를 높이게 되면 높은 발열과 전력소모량, 하드웨어적인 이슈로 인해 한계점이 존재

코어와 멀티코어

  • 코어
    • 전통적인 관점에서의 ‘명령어를 실행하는 부품’은 하나만 존재하지만 오늘날엔 여러 개가 존재한다.
    • ‘명령어를 실행하는 부품’을 코어라는 용어로 사용하고 있다.

많이 발전했네! 🥳

 

  • 멀티코어
    • 여러 개의 코어를 포함하고 있는 CPU
  • 코어를 증가함에 따라 비례적으로 CPU의 연산 속도가 증가하는가? ➡️ 그건 아님 (조별과제 😤)
  • 코어마다 처리할 명령어를 적절하게 분배하는 것에 따라 멀티코어의 연산 속도가 크게 달라진다.

스레드와 멀티스레드

  • 두가지의 종류로 구분지어 기억

 

하드웨어적 스레드 : 하나의 코어가 동시에 처리하는 명령어 단위

  • 하나의 코어에서 2개의 명령어를 동시에 처리할 수 있다면 1코어당 2스레드를 가진다. : 멀티스레드 CPU

딱 봐도 빨라 보인다.

 

✅ 하이퍼 스레딩 : 인텔 사의 멀티스레드 기술을 지칭

 

소프트웨어적 스레드 : 하나의 프로그램에서 독립적으로 실행되는 단위

  • 하나의 프로그램에서 동시에 여러개의 영역이 동시에 실행된다.

1클럭에서 여러군데의 메모리 접근이 발생하면 멀티스레드 🤔

 

  • 1코어 1스레드의 CPU도 소프트웨어적으로 여러 스레드를 만들 수 있다.

 

멀티스레드 프로세서

  • 멀티스레드 프로세서를 설계하는 것은 매우 복잡 ➡️ 핵심은 레지스터
  • 하나의 명령어를 실행하기 위해 꼭 필요한 레지스터들을 편의상 ‘레지스터 세트’라고 표기 ➡️ 레지스터 세트가 여러개 있다면 하나의 코어가 여러개의 명령어를 실행할 수 있다.

레지스터 세트가 여러개!! 부자 된 기분!! 🤑

 

  • 멀티 스레드(ex. n스레드)의 작업 수행시 메모리 입장에선 작업 흐름이 동시에 n개 존재할 수 있다.
  • 메모리의 입장에선 하나의 명령어를 처리하는 CPU가 n개 있는 것처럼 보인다. ➡️ 그래서 하드웨어 스레드를 논리 프로세서(logical processor)라고 부르기도 한다.

05-2 명령어 병렬 처리 기법

명령어 파이프라인

  • 명령어가 처리 되는 과정을 비슷한 시간 간격으로 나누면?
    1. 명령어 인출(Instruction Petch)
    2. 명령어 해석(Instruction Decode)
    3. 명령어 실행(Execute Instruction)
    4. 결과 저장 (Write Back)
    ✅ 명령어 인출 ➡️ 명령어 실행으로 나누기도 하고, 명령어 인출 ➡️ 명령어 해석 ➡️ 메모리 접근 ➡️ 결과 저장으로 나누기도 한다.
  • 같은 단계가 겹치지만 않으면 CPU는 ‘각 단계를 동시에 실행할 수 있다’

단위 시간(tn)마다 실행되는 명령어들, 1클럭당 실행되는 명령어인가?! 👻👻

 

  • t2의 경우 명령어 1의 실행과 명령어 2의 해석과 명령어 3의 인출을 동시에 실행 중이다.
  • 명령어들을 명령어 파이프라인에 넣고 동시에 처리하는 기법을 명령어 파이프라이닝이라고 한다.
  • 파이프라인 위험 : 파이프라이닝으로 특정 상황에서 성능 향상에 실패하는 경우

파이프라인 위험의 3 종류

 

이터 위험

  • 명령어 간 의존성에 의해 발생
  • 모든 명령어를 동시에 처리할 수는 없다 ➡️ 이전 명령어를 끝까지 실행해야만 비로소 실행할 수 있는 경우

제어 위험

  • 프로그램 카운터의 갑작스러운 변화 : JUMP 명령어 같은 것
  • 명령어 파이프라인에 미리 가지고 와서 처리 중이었던 명령어들이 아무 쓸모 없어짐
  • 분기 예측(branch prediction) : 프로그램이 어디로 분기할지 미리 예측한 후 그 주소를 인출하는 기술로 예방한다.

으악! 기껏 파이프라이닝으로 열심히 작업했는데!! 🙀

 

구조적 위험

  • 서로 다른 명령어가 같은 CPU 부품(ALU, 레지스터)를 쓰려고 할 때 발생
  • 자원 위험(resource hazard)이라고도 부른다.

슈퍼스칼라

  • CPU 내부에 여러 개의 명령어 파이프라인을 포함한 구조 (오늘날의 멀티스레드 프로세서)

명령어 파이프라인 그림과 다른점은 단위시간에 같은 명령어를 2개씩 처리하고 있다는 점! 🤭

  • 이론적으로는 파이프라인 개수에 비례해서 처리 속도가 증가
  • 하지만 파이프라인 위험도의 증가로 인해 파이프라인 개수에 비례해서 처리 속도가 증가하진 않음

비순차적 명령어 처리

  • OoOE : Out of order execution
  • 명령어들간의 합법적인 새치기

합법이라도 열 받을거 같은데? 😡

 

  • 의존성이 없는 명령어의 순서를 바꿔서 파이프라인 위험을 벗어나 실행된다.
  • 명령어를 순차적으로만 실행하지 않고 순서를 바꿔 실행해도 무방한 명령어를 먼저 실행하여 명령어 파이프라인이 멈추는 것을 방지하는 기법 ➡️ 비순차적 명령어 처리 기법
  • 비순차적 명령어 처리가 가능한 CPU는 명령어들이 어떤 명령어와 데이터 의존성을 가지고 있는지, 순서를 바꿔 실행할 수 있는 명령어에는 어떤 것들이 있는지를 판단할 수 있어야 한다.

✅ 요약 : 비순차적 명령어 처리 기법은 파이프라인의 중단을 방지하기 위해 명령어를 순차적으로 처리하지 않는 명령어 병렬 처리 기법

 

05-3 CISC와 RISC

명령어 집합 (구조)

  • 명령어 집합 또는 명령어 집합 구조 (이하 ISA) : CPU가 이해할 수 있는 명령어들의 모음
  • ISA가 다르면 서로의 명령어를 이해할 수 없기 때문에 ISA는 일종의 CPU의 언어인 셈
  • ISA가 다르면 생김새 뿐만 아니라 제어장치가 명령어를 해석하는 방식, 사용하는 레지스터의 종류와 갯수 등 CPU 하드웨어 설계에도 영향을 미친다.

소프트웨어'만' 다른게 아니라 파급력이 크다!

 

CISC (Complex Instruction Set Computer)

  • 복잡한 명령어 집합을 활용하는 컴퓨터 (CPU)
  • x86, x86-64는 CISC 기반 명령어 집합 구조를 이용하고 있다.
  • 복잡하고 다양한 명령어 활용
  • 명령어의 형태와 크기가 다양한 가변 길이의 명령어를 활용

CISC의 매력어필 🤗

 

  • 다양하고 강력한 명령어를 활용
  • 상대적으로 적은 수의 명령어로도 프로그램을 실행할 수 있다.
  • 메모리를 최대한 아끼며 개발해야 했던 시절에 인기가 높았음
  • 명령어 파이프라이닝이 불리하다는 치명적인 단점이 존재
    • 명령어가 워낙 복잡하고 다양한 기능을 제공하는 탓에 명령어의 크기와 실행되기까지의 시간이 일정하지 않음
    • 복잡한 명령어 때문에 명령어 하나를 실행하는 데에 여러 클럭 주기가 필요
    • 대다수의 복잡한 명령어는 사용 빈도가 낮다.

매력어필에 넘어갈뻔 했는데 이런 치명적인 단점이?

 

RISC (Reduced Instruction Set Computer)

  • 명령어의 종류가 적고, 짧고 규격화된 명령어 사용

레고 블럭 조립하듯이 차곡차곡

  • 명령어 파이프라이닝에 유리함
  • 메모리 접근 최소화 (load, store만 사용하도록 제한), 레지스터를 십분 활용한다.
    • CISC 보다 범용 레지스터가 더 많다.
  • 사용 가능한 명령어 개수가 CISC보다 적기 때문에 CISC보다 더 많은 명령어로 프로그램을 동작

 

ISA 차이점 요약 도표

CISC RISC
복잡하고 다양한 명령어 단순하고 적은 명령어
가변 길이 명령어 고정 길이 명령어
다양한 주소 지정 방식 적은 주소 지정 방식
프로그램을 이루는 명령어의 수가 적음 프로그램을 이루는 명령어의 수가 많음
여러 클럭에 걸쳐 명령어를 수행 1클럭 내외로 명령어 수행
파이프라이닝하기 어려움 파이프라이닝하기 쉬움

✅ 요즘 CPU에선 CISC라도 단점을 보완하고자 CISC의 실제 실행시에 명령어를 마이크로 명령어로 쪼개어 수행하여 내부적으론 RISC 처럼 동작한다.

커리큘럼 🫠


📃 기본 미션1

다음 설명의 빈칸에 들어갈 알맞은 내용을 써 보세요.

프로그램이 실행되려면 반드시 (     )에 저장되어 있어야 합니다.

🖍 메모리, 램, RAM, 주기억장치

 

📃 기본 미션2

1101₍₂₎의 음수를 2의 보수 표현법으로 구해 보세요.

사진이 흐리다... 🥲

🖍 2의 보수 표현법은 2단계로 나누어진다.

1단계 : 모든 0과 1을 뒤집는다.

2단계 : 1을 더한다.

 

고로 1101의 경우 1단계에서 0010이 되며

2단계에서 0011이 된다.


📃 선택 미션

스택과 큐의 개념을 정리하기

스택(stack)?
가장 먼저 입력된 자료가 가장 나중에 출력되는 자료형
push(add)와 pop(delete) 연산이 한 곳에서 발생되는 자료구조(LIFO, 후입선출)

실제로 이렇게 생긴건 아니고 추상화한 형태가 이렇다.
자료는 1,2,3의 순서로 입력되고 3,2,1의 순서로 출력된다.

큐(queue)?
가장 먼저 입력된 자료가 가장 먼저 출력되는 자료형
한쪽에서는 삽입연산만 발생 가능하고, 다른 한쪽에서는 삭제연산만 발생 가능한 자료구조(FIFO, 선입선출)

스택과 마찬가지로 추상화된 형태의 큐
자료는 1,2,3의 순서로 입력되고 1,2,3의 순서로 출력된다.


Chapter 1️⃣

컴퓨터 구조를 알아야 하는 이유

  • 컴퓨터 작업의 문제 해결의 실마리를 다양하게 찾을 수 있다. 다양한 문제를 스스로 해결할 줄 아는 개발자가 되기 위한 소양 즉 문제 해결 능력이 향상된다.
  • 서비스 제공에서 필연적으로 고려되는 성능, 용량, 비용 문제에 대한 사고능력 증진
  • 컴퓨터 구조를 이해하면 우리는 컴퓨터를 미지의 대상에서 분석의 대상으로 인식하게 된다.

컴퓨터 구조의 큰 그림

1. 컴퓨터가 이해하는 정보

  • 컴퓨터는 0과 1로 표현된 정보 (데이터, 명령어)를 이해한다.
  • 데이터
    • 컴퓨터가 이해하는 숫자, 문자, 이미지, 동영상과 같은 정적인 정보
    • 컴퓨터와 주고 받는 정보, 컴퓨터에 저장된 정보를 가르키기도 한다.
  • 명령어
    • 컴퓨터를 실질적으로 작동시키는 중요한 정보
    • 데이터를 움직이고 컴퓨터를 작동시키는 정보

2. 컴퓨터의 핵심 부품

  • 중앙처리장치(CPU)
    • CPU는 메모리에 저장된 값을 읽어 들이고, 해석하고, 실행하는 장치이다.
    • ALU : 산술논리연산장치, 컴퓨터 내부에서 수행되는 대부분의 계산을 수행
    • 레지스터 : CPU 내부의 작은 임시 저장 장치, 여러 개의 레지스터가 존재하고 각기 다른 이름과 역할을 가지고 있음
    • 제어장치 : 제어신호를 내보내고 명령어를 해석하는 장치, 컴퓨터 부품을 관리하고 작동시키기 위해 필수
  • 주기억장치(메모리)
    • 메모리는 현재 실행되는 프로그램의 명령어와 데이터를 저장하는 부품
    • 프로그램이 실행되려면 반드시 메모리에 저장되어 있어야 한다.
    • 주소(address) : 메모리에 저장된 값에 빠르고 효율적으로 접근하기 위한 위치 식별자
  • 보조기억장치
    • 전원이 꺼져도 저장된 내용을 잃지 않는, 메모리를 보조할 저장 장치
    • 일반적으로 주기억장치 보다 가격이 저렴하다.
  • 입출력장치
    • 마이크, 스피커, 프린터, 마우스, 키보드 등 컴퓨터 외부에 연결되어 컴퓨터 내부와 정보를 교환하는 장치 

✅ 메인보드와 시스템 버스메인보드에 연결된 부품들은 버스(bus)라는 데이터 전송 역할을 하는 통로로 정보를 주고 받는다.시스템 버스는 주소버스, 데이터 버스, 제어 버스로 구성되어있다.

  • 핵심 부품 4가지를 연결하는 가장 중요한 버스는 시스템 버스이다.
  • 컴퓨터 핵심부품은 모두 메인보드에 연결된다.

메인보드에 연결된 핵심부품들


Chapter 2️⃣

정보 단위

  • 0과 1을 나타내는 가장 작은 정보 단위를 비트(bit)라고 한다.
  • 8개의 비트를 묶어서 바이트(byte)라 하고 2⁸ (256)개의 정보를 표현한다.
  • 1바이트를 1000개 묶어서 1 킬로바이트
  • 1킬로바이트를 1000개 묶어서 1메가바이트
  • 1메가바이트를 1000개 묶어서 1기가바이트
  • 1기가바이트를 1000개 묶어서 1테라바이트

✅ 1024로 묶은 단위는 KiB, MiB, GiB, TiB이다.

✅ 워드(word) : CPU가 한 번에 처리할 수 있는 데이터 크기를 의미한다.

  • 워드의 절반 크기를 하프 워드(half word), 1배 크기를 풀 워드(full word), 2배 크기를 더블 워드(double word)라고 한다.
  • 현대 컴퓨터는 대부분 32비트 혹은 64비트의 워드 크기를 가진다.

이진법

  • 0과 1로 숫자를 표현한다.
  • 1000₍₂₎ 혹은 0b1000의 표기 형식을 가진다.

이진수의 음수 표현

  • 가장 널리 사용되는 방법은 2의 보수를 구해 음수로 간주하는 방법이 있다.
  • ‘어떤 수를 그보다 큰 2ⁿ 에서 뺀 값’
  • 간단하게 구하는 방법
    • 1단계 : 모든 0과 1을 뒤집는다.
    • 2단계 : 1을 더한다.
  • 컴퓨터 내부에서는 양수인지 음수인지를 구분하기 위해 플래그를 사용한다. (ex. flag가 음수면 이진수 값을 음수로 인지한다.)
  • 2의 보수를 취하는 방식은 널리 사용되지만 n비트로 -2ⁿ 과 2ⁿ 이라는 수를 동시에 표현 할 수 없다

십육진법

  • 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F 로 16진법을 표시한다.
  • 15₍₁₆₎ 혹은 0x15의 표기 형식을 가진다.
  • 이진수와의 변환이 쉽기 때문에 쓰인다.

문자 집합

  • 컴퓨터가 인식하고 표현할 수 있는 문자의 모음

문자 인코딩

  • 문자를 0과 1로 변환하는 과정을 문자 인코딩이라 한다.

문자 디코딩

  • 인코딩의 반대 과정으로 0과 1로 이루어진 문자 코드를 사람이 이해할 수 있는 문자로 변환하는 과정

아스키 코드

  • 초창기의 문자 집합, 8비트 중 패리티 비트를 제외한 7비트로 문자를 나타낸다. 즉 2⁷ 개 (128개)의 문자를 표현할 수 있다.

EUC-KR

  • 완성형 인코딩 : 초성, 중성, 종성의 조합으로 이루어진 완성된 글자 하나에 고유한 코드를 부여하는 방식
  • 조합형 인코딩 : 자음 모음에 비트열을 할당하여 그것들을 조합하여 글자 코드를 완성하는 방식
  • EUC-KR은 2바이트 크기로 인코딩 할 수 있는 완성형 인코딩 방식이다.
  • 총 2350개의 한글 단어를 표현할 수 있지만 모든 글자를 표현할 순 없다.

유니코드와 UTF-8

  • 여러 나라의 문자를 광범위하게 표현할 수 있는 통일된 문자 집합
  • 현대 문자를 표현할 때 가장 많이 사용되는 표준 문자 집합
  • 인코딩 방법에는 크게 UTF-8, UTF-16, UTF-32 등이 존재한다.

X로 표기된 부분에 이진수 값이 위치하는 것이 UTF-8의 인코딩 결과이다.


 

Chapter 3️⃣

고급 언어

  • 사람이 이해하고 작성하기 쉽게 만들어진 언어

저급 언어

  • 컴퓨터가 직접 이해하고 실행 할 수 있는 언어
  • 기계어, 어셈블리어가 있다.

기계어

  • 0과 1의 명령어 비트로 이루어진 언어
  • 오로지 컴퓨터만을 위해 만들어진 언어로 사람이 읽으면 의미를 이해하기 어렵다.

어셈블리어

  • 사람이 읽기 편한 형태로 번역한 저급 언어
  • 그래도 이해하기 쉽지 않아 복잡한 프로그램 개발엔 사용하기 힘들다.

컴파일 언어

  • 컴파일러에 의해 소스 코드 전체가 저급 언어로 변환되어 실행되는 고급 언어
  • 소스 코드를 저급 언어로 변환하는 과정을 컴파일(compile)이라고 한다.
  • 컴파일을 수행해주는 도구를 컴파일러(compiler)라고 한다.
  • 소스 코드에서 문법적인 오류나 실행 불가능한 코드인지 따져 컴파일에 실패하기도 한다.
  • 컴파일러를 통해 저급언어로 변환된 코드를 목적 코드(object code)라고 한다.
  • 원론적으로 소스코드 전체를 살펴보고 컴파일을 수행한다.

인터프리터 언어

  • 인터프리터에 의해 한 줄씩 실행되는 고급 언어
  • 소스 코드를 한 줄씩 저급 언어로 변환하여 실행해 주는 도구를 인터프리터(interpreter)라고 한다.
  • 소스코드 전체가 변환되길 기다릴 필요가 없다.
  • 일반적으로 컴파일 언어보다 실행 속도가 느리다. (한 줄씩 해석해야하기 때문)

명령어의 구조

  • 연산코드 : 명령어가 수행할 연산, 연산자
  • 오퍼랜드 : 연산에 사용될 데이터 혹은 연산에 사용될 데이터가 저장될 위치, 피연산자
  • 연산 코드가 담기는 영역을 연산 코드 필드라 하고 오퍼랜드가 담기는 영역을 오퍼랜드 필드라고 한다.

오퍼랜드

  • 연산에 사용할 데이터 또는 연산에 사용할 데이터가 지정된 위치
  • 오퍼랜드 필드엔 데이터 주소값이 자주 저장되어 주소필드라고도 부른다.
  • 오퍼랜드가 명령어 안에 하나도 없는 명령어를 0-주소 명령어라고 한다.
  • 오퍼랜드가 명령어 안에 하나인 명령어를 1-주소 명령어라고 한다.
  • 오퍼랜드가 명령어 안에 두 개인 명령어를 2-주소 명령어라고 한다.
  • 오퍼랜드가 명령어 안에 세 개인 명령어를 3-주소 명령어라고 한다.

연산코드

  • 명령어가 수행할 연산을 의미
  • CPU마다 다르기 때문에 연산코드의 종류와 기능 정도만 알아 둘 것

연산코드의 종류

  • 데이터 전송
    • MOVE : 데이터를 옮겨라
    • STORE : 메모리에 저장하라
    • LOAD(FETCH) : 메모리에서 CPU로 제이터를 가져와라
    • PUSH : 스택에 데이터를 저장하라
    • POP : 스택의 최상단 데이터를 가져와라
  • 산술/논리 연산
    • ADD / SUBTRACT / MULTIPLY / DIVIDE : 덧셈 / 뺄셈 / 곱셈 / 나눗셈을 수행하라
    • INCREMENT / DECREMENT : 오퍼랜드에 1을 더하라 / 오퍼랜드에 1을 빼라
    • AND / OR / NOT : 논리연산을 수행하라
    • COMPARE : 두 개의 숫자 또는 TRUE / FALSE 값을 비교하라
  • 제어 흐름 변경
    • JUMP : 특정 주소로 실행 순서를 옮겨라
    • CONDITIONAL JUMP : 조건에 부합할 때 특정 주소로 실행 순서를 옮겨라
    • HALT : 프로그램의 실행을 멈춰라
    • CALL : 되돌아올 주소를 저장한 채 특정 주소로 실행 순서를 옮겨라
    • RETURN : CALL을 호출할 때 저장했던 주소로 돌아가라
  • 입출력 제어
    • READ (INPUT) : 특정 입출력 장치로부터 데이터를 읽어라
    • WRITE (OUTPUT) : 특정 입출력 장치로 데이터를 써라
    • START IO : 입출력 장치를 시작하라
    • TEST IO : 입출력 장치의 상태를 확인하라

주소 지정 방식 (addressing modes)

  • 연산에 사용할 데이터가 저장된 위치를 찾는 방법, 유효 주소를 찾는 방법, 다양한 명령어 주소 지정 방식이 있다.
  • 앞서 언급한 오퍼랜드 필드에 메모리나 레지스터의 주소를 담는 이유
    • 명령어의 길이 때문에 표현 할 수 있는 데이터가 한정적이기 때문
    • 오퍼랜드 필드에 메모리 주소가 담긴다면 표현할 수 있는 데이터의 크기는 하나의 메모리 주소에 저장할 수 있는 공간만큼 커진다.

✅ 유효주소(effective address) : 연산에 사용할 데이터가 저장된 위치

 

 

1. 즉시 주소 지정 방식 (immediate addressing mode)

  • 연산에 사용할 데이터를 오퍼랜드 필드에 직접 명시하는 방식
  • 연산에 사용할 데이터를 메모리나 레지스터로부터 찾는 과정이 없기 때문에 속도가 빠르다.

2. 직접 주소 지정 방식 (direct addressing mode)

  • 오퍼랜드 필드에 유효 주소를 직접적으로 명시하는 방식
  • 유효 주소를 명시하는데에 한계가 있다. (즉시 주소 지정 방식과 동일한 문제 : 명령어의 길이)

3. 간접 주소 지정 방식 (indirect addressing mode)

  • 유효 주소의 주소를 오퍼랜드 필드에 명시하여 유효 주소의 범위가 넓다.
  • 두 번의 메모리 접근이 필요하기 때문에 일반적으로 느린 방식

4. 레지스터 주소 지정 방식 (register addressing mode)

  • 직접 주소 지정 방식과 비슷하게 연산에 사용할 데이터를 저장한 레지스터 주소 값을 오퍼랜드에 명시하는 방법
  • 메모리에 접근하는 것보단 더 빠르다.
  • 직접 주소 지정 방식과 동일하게 유효 주소를 명시하는데에 한계가 있다.

5. 레지스터 간접 주소 지정 방식 (register indirect addressing mode)

  • 연산에 사용할 데이터를 메모리에 저장하고, 유효 주소를 저장한 레지스터를 오퍼랜드 필드에 명시하는 방법
  • 메모리에 접근하는 횟수가 한 번으로 간접 주소 지정 방식보다 빠르다.

+ Recent posts