반응형

이 글은  컴퓨터 밑바닥의 비밀 chapter 6.5의 내용을 읽고 요약한 글입니다. 

 

6.5 mmap: 메모리 읽기와 쓰기 방식으로 파일 처리

코드에서 메모리를 읽기 쓰는 것은 아래와 같이 배열을 정의하고 값을 할당하기만 하면 됨

int a[100];
a[10] = 2;

하지만 파일을 읽는 경우는 상대적으로 더 복잡

char buf[1024];

int fd = open("/filepath/abc.txt");
read(fd, buf, 1024);
// buf 등을 이용한 작업
  • 운영체제에 파일에 접근할 수 있는 파일 서술자를 요청 후 파일의 정보를 읽을 수 있음

파일을 사용하는 것이 메모리를 사용하는 것보다 복잡한 이유

  1. 디스크에서 특정 주소를 지정(addressing)하는 방법과 메모리에서 특정 주소를 지정하는 방법이 다름
  2. CPU와 외부 장치 간 속도에 차이가 있음

파일에 대해 메모리처럼 직접 디스크의 파일을 읽고 쓸 수는 없을까?

6.5.1 파일과 가상 메모리

  • 사용자 상태에서 메모리는 하나의 연속된 공간이고, 디스크에 저장된 파일도 하나의 연속된 공간
  • 두 공간을 연관 짓는 방법은? → 가상 메모리
  • 가상 메모리의 목적은 모든 프로세스가 각자 독점적으로 메모리를 소유하고 있다고 생각하게 하는 것
  • 프로세스가 만나는 주소 공간은 가상이기 때문에 ‘수작을 부려’작업할 수 있는 공간이기도 함
  • 파일은 개념적으로 연속된 디스크 공간에 저장되어 있다고 생각할 수 있으므로 이 공간을 프로세스 주소 공간에 직접 mapping할 수 있음
    • 길이가 200바이트인 파일을 프로세스 주소 공간에 매핑한 결과로 파일이 600~799 주소 범위에 위치하고 있다고 가정하면, 이 주소 공간에서 바이트 단위로 파일을 처리할 수 있음

6.5.2 마술사 운영 체제

  • 600~799 범위의 주소 공간을 읽을 때, 대응하는 파일이 아직 메모리에 적재되지 않아 페이지 누락(page fault) 인터럽트가 발생할 수 있음
  • 이후 CPU가 운영 체제의 인터럽트 처리함수를 실행하며, 실제 디스크 입출력 요청이 시작
  • 파일을 메모리로 읽고 가상 메모리와 실제 메모리의 연결이 수립되면 프로그램에서 메모리를 읽고 쓰듯이 직접 디스크의 내용을 사용할 수 있음
  • mmap을 사용하더라도 실제로 디스크를 읽고 써야 하기는 하지만 이 과정은 운영체제가 진행함
  • 또한 가상 메모리를 경유하기 때문에 고수준 계층에 있는 사용자는 신경쓸 필요 없음

6.5.3 mmap 대 전통적인 read/write 함수

  • read/write 함수 같은 입출력 함수는 저수준 계층에 시스템 호출을 사용함 → 파일을 읽고 쓸 때 데이터를 커널 상태 ↔ 사용자 상태로 복사해야 해서 큰 부담을 수반
  • mmap은 디스크의 파일을 읽고 쓸 때는 시스템 호출과 데이터 복사가 주는 부담이 없음. 하지만 커널은 프로세스 주소 공간관 파일의 mapping 관계를 유지하기 위해 특정 데이터 구조를 사용해야 하며 이 역시 성능에 부담을 가져옴
  • 이외에 page fault 문제가 있어 인터럽트가 발생하면 이에 상응하는 인터럽트 처리 함수가 실제로 파일을 메모리에 적재해야 함

⇒ mmap 과 read/write 함수의 성능 비교를 할 때 실제 구체적인 상황에서 각각의 방식에 대한 부담을 비교하여 선택해야 함

6.5.4 큰 파일 처리

  • 큰 파일이란 물리 메모리 용량을 초과할 정도의 크기를 가진 파일을 의미
  • 전통적인 read/write 함수를 사용하면 파일을 조금씩 나누어 메모리에 적재해야 하며, 파일의 일부분에 대한 처리가 끝나면 다시 다음 부분에 대한 처리를 하는 방식으로 너무 많은 메모리를 요청하면 OOM 문제가 발생할 수 있음
  • mmap을 사용하면 가상 메모리의 도움하에 프로세스 주소 공간이 충분하다면 큰 파일 전체를 프로세스 주소 공간에 직접 mapping할 수 있으며 해당 파일의 크기가 실제 물리 메모리의 크기보다 크더라도 아무 문제 없음
  • mmap을 호출할 때 매개변수가 MAP_SHARED 라면 사상된 영역의 변경 내용은 디스크의 파일에 직접 기록됨. 시스템은 작업중인 파일의 크기가 물리 메모리의 크기보다 큰지 전혀 관심 없음
  • 매개변수가 MAP_PRIVATE 인 경우, 시스템이 실제로 메모리를 할당한다는 의미로 물리 메모리의 크기에 교환 영역(swap area)의 크기를 더한 크기가 기준이 됨

6.5.5 동적 링크 라이브러리와 공유 메모리

  • 동적 링크 라이브러리의 경우 이를 차조하는 프로그램이 아무리 많더라도 실행 파일에는 라이브러리의 코드와 데이터가 포함되지 않음
  • 라이브러리를 참조하는 모든 프로그램이 메모리에 적자되더라도 동일한 동적 라이브러리를 공유하므로 디스크와 메모리의 공간을 절약할 수 있음

mmap으로 해당 라이브러리를 사용하는 모든 프로세스의 주소 공간에 직접 mapping할 수 있는데 여러 프로세스는 모두 해당 라이브러리가 자신의 주소 공간에 적재되었다고 생각하지만, 실제 물리 메모리에서 이 라이브러리가 차지하는 공간은 한개 크기일 뿐임.

반응형
반응형

이 글은  컴퓨터 밑바닥의 비밀 chapter 6.4의 내용을 읽고 요약한 글입니다. 

 

6.4.1 파일 서술자

  • 모든 입출력 작업은 파일 읽기와 쓰기로 구현할 수 있음

read 함수를 이용해 파일 내용을 읽을 때 아래와 같이 사용하는데 어디에서 데이터를 읽는가?

read(buffer);
  • 유닉스/리눅스 세계에서 파일을 사용하려면 번호를 필요로하는데 이를 파일 서술자(file descriptor)라고 함. 즉 파일 서술자는 숫자에 불과
  • 프로그래머는 파일 서술자라는 숫자를 통해 입출력을 처리할 수 있음
  • 파일이 디스크에 저장되어있는지, 디스크는 어느 위치에 저장되어 있는지 등의 정보를 운영체제가 대신 처리하므로 프로세스는 이를 신경쓸 필요없음
char buffer[LEN];
int fd = open(file_name); // 파일 서술자 얻기

read(fd, buffer);

6.4.2 다중 입출력을 어떻게 효율적으로 처리하는 것일까?

  • 높은 동시성이란 서버가 동시에 많은 사용자 요청을 처리할 수 있음을 의미
  • 웹 서버에서 3way handshake에 성공하면 accept 함수를 호출하여 연결을 얻을 수 있고, 추가로 파일 서술자도 얻을 수 있음. 파일 서술자로 사용자와 통신을 진행
// accept 함수로 사용자의 파일 서술자 획득
int conn_fd = accept(...);
  • 서버의 처리 작동 방식은 일반적으로 먼저 사용자 요청 데이터를 읽고, 이에 따라 특정한 처리를 실행
if(read(conn_fd, buff) > 0)
{
	do_something(buff);
}
  • read 함수는 일반적으로 블로킹 입출력인데 높은 동시성을 위해서는 파일 서술자 수천수만 개를 처리해야 함
  • 다중 스레드를 생각할 수 있지만 이 방법은 스레드 수가 너무 많아질 수 있고 스레드의 스케쥴링과 전환에 너무 많은 부담이 가해지므로 최적의 방법이 아닐 수 있음

6.4.3 상대방인 아닌 내가 전화하게 만들기

  • 여러개의 파일 서술자에 대해 읽고 쓸 수 있는지 매번 체크하는 것이 아니라 관심 대상인 파일 서술자를 커널에 알려주고, 커널에 대신 감시하다가 읽고 쓸 수 있는 파일 서술자가 있을 때 알려주면 처리하겠다고 이야기 하는 것 ⇒ 입출력 다중화(input/output multiplexing) 기술

6.4.4 입출력 다중화

  • 다중화(multiplexing)라는 용어는 사실 통신 분야에서 많이 사용되는데 통신 선로를 최대한 활용하기 위해 하나의 채널에서 여러 신호를 전송할 수 있어야 함 → 여러 신호를 하나로 합칠 필요가 있음. 여러 신호를 하나로 합치는 장치를 다중화기(multiplexer)라고 함
  • 이 신호를 수신하는 쪽에서는 합쳐진 신호를 다시 원래의 여로 신호로 복원해야 하는데 이 장치를 역다중화기(demultiplexer)라고 함

참고: https://velog.io/@seokjun0915/데이터통신-Multiplexing-1

 

입출력 다중화는 아래 과정을 의미

  1. 파일 서술자를 획득. 서술자 종류는 상관없음
  2. 특정 함수를 호출하여 커널에 다음과 같이 알림. ‘이 함수를 먼저 반환하는 대신, 이 파일 서술자를 감시하다 읽거나 쓸 수 있는 파일 서수자가 나타날 때 반환해주세요’
  3. 해당 함수가 반환되면 읽고 쓸 수 있는 조건이 준비된 파일 서술자를 획득할 수 있으며 이를 통해 사응하는 처리를 할 수 있음

이 기술로 여러 입출력을 한꺼번에 처리할 수 있음. 리눅스에서는 입출력 다중화 기술을 사용하는 방법에 3가지가 있음

 

6.4.5 삼총사: select, poll, epoll

  • 본질적으로 select, poll, epoll은 모두 동기 입출력 다중화 기술
  • 이런 함수가 호출될 때 감시해야 하는 파일 서술자에서 읽기/쓰기 가능 같은 관심 대상 이벤트가 나타나지 않으면 호출된 스레드가 블로킹되어 일시 중지되고, 파일 서술자가 해당 이벤트를 생성할 때까지 함수는 반환되지 않음

select

  • 감시할 수 있는 파일 서술자 묶음에 제한이 있으며 일반적으로 1024개를 넘을 수 없음
  • select가 호출될 때 대응하는 프로세스 또는 스레드는 감시 대상인 파일의 대기열에 배치되므로 select 호출로 브로킹되며 일시 중지 됨
  • 파일 서술자 중 하나라도 읽기 가능 또는 쓰기 가능 이벤트가 나타나면 해당 프로세스 또는 스레드가 다시 깨어남

→ 문제는 프로세스가 깨어났을 때 프로그래머는 어떤 파일 서술자가 읽고 쓸 수 있는지 알 수 없어, 준비완료 상태의 팡리 서술자를 알기 위해 처음부터 끝까지 다시 확인해야 함. 대량의 파일 서술자를 감시할 때 효율이 매우 떨어지는 근본적인 원인

poll

  • select와 매우 유사하지만 최적화된 점은 감시 가능한 파일 서술자 수가 1024개 이상이라는 것
  • 하지만 select와 마찬가지로 파일 서술자 수가 늘어날수록 성능이 저하되는 문제가 있음

epoll

  • 커널에 필요한 데이터 구조를 생성하며 준비 완료된 파일 서술자 목록을 가짐
  • 감시되고 있는 파일 서술자에서 관심 이벤트가 발생하면 해당 프로세스를 깨우면서 준비 완료된 파일 서술자가 준비 완료 목록에 추가 됨
  • 프로세스와 스레드에서 모든 파일 서술자를 처음부터 끝까지 확인할 필요 없이 준비완료된 파일 서술자를 직접 획득할 수 있는데 이는 매우 효율적
반응형
반응형

이 글은  컴퓨터 밑바닥의 비밀 chapter 6.3의 내용을 읽고 요약한 글입니다. 

6.3.1 메모리 관점에서 입출력

  • 단순히 메모리의 복사(copy)일 뿐, 그 이상도 이하도 아님
  • 그럼 파일 내용을 읽는 것을 예로 들면, 데이터는 잔치에서 프로세스 주소 공간으로 어떻게 복사될까?

6.3.2 read 함수는 어떻게 파일을 읽을까?

  • 단일 코어 CPU 시스템에 프로세스 A와 프로세스 B 두개가 있고, 프로세스 A가 현재 실행중이라고 가정
1. (속에) put (sth in/into sth); (끼우다) insert; (채우다) pack, stuff
2. (손에) get, obtain, come by
3. (추가하다) add, include

 

  • 프로세스 A에는 파일을 읽는 코드가 있고, 먼저 데이터를 저장하는 버퍼를 정의 후 다음과 같이 read 계열의 함수를 호출
char buffer[LEN];
read(buffer);
  • 저수준 계층에서 시스템 호출을 이용하여 운영체제에 파일 읽기 요청을 보냄
  • 요청은 커널에서 디스크가 이해할 수 있는 명령어로 변환되어 디스크로 전송
  • CPU가 명령어를 실행하는 속도에 비해 디스크 입출력은 매우 느려 운영체제는 귀중한 계산 리소스를 불필요한 대기에 낭비할 수 없음
  • 운영체제는 현재 프로세스(프로세스 A)의 실행을 일시 중지하고 입출력 블로킹 대기열에 넣음

  • 운영체제는 이미 디스크에 입출력 요청을 보낸 상태이며 데이터를 특정 메모리 영역으로 복사하는 작업 시작

 

프로세스 B는 준비 완료 대기열에 들어감

 

  • CPU 코어수에 비해 프로세스의 수가 훨씬 많음. 그래서 이미 다시 실행될 준비가 된 프로세스가 있더라도 바로 CPU가 할당되지 못할 수 있기 때문에 준비 완료 대기열에 들어감

프로세스 A가 블로킹 입출력 요청을 시작해서 일시 중지되더라도 CPU는 쉬지 않고 준비 완료 대기열에서 실행할 수 있는 프로세스를 찾아 실행

  • 프로세스 B는 CPU가 실행하고 있으며 디스크는 프로세스 A의 메모리 공간에 데이터를 쓰고 있음

 

  • 이후 데이터가 프로세스 A의 메모리에 복사하는 작업이 완료되면, 디스크는 CPU에 인터럽트 신호를 보냄
  • CPU는 인터럽트 신호를 받은 후 처리가 중단되었던 함수로 점프, 디스크의 입출력 처리가 완료되었음을 알게 됨
  • 운영체제는 프로세스 A를 입출력 블로킹 대기열에서 꺼내 다시 준비 완료 대기열에 넣음

  • 운영체제는 CPU를 프로세스 A에 할당할지, B에 할당할 지 결정해야 함 → 프로세스 B에 할당된 CPU 시간이 아직 남아 계속 B를 실행하는 것으로 가정
  • 프로세스 A는 계속 대기하고, 일정 시간 후 타이머 인터럽트 신호가 발생하면 운영체제는 프로세스 B를 준비 완료 대기열로 넣음과 동시에 프로세스 A를 준비 완료 대기열에서 꺼내 CPU를 할당

반응형
반응형

이 글은  컴퓨터 밑바닥의 비밀 chapter 6.2의 내용을 읽고 요약한 글입니다. 

  • 최신 컴퓨터 시스템의 경우, 사실 디스크가 입출력을 처리할 때 CPU개입이 필요하지 않음. 이유는? 아래의 장치 제어기, 직접 메모리 접근, 인터럽트의 관계를 이해해야 함
  • 디스크 입출력 요청을 처리하는 동안 운영 체제는 CPU가 다른 작업을 수행하도록 스케쥴링함

상황

  • CPU가 스레드 1을 실행하기 시작하고 일정 시간 지난 후 파일 읽기와 같은 디스크 관련 입출력을 요청한다고 가정
  • 디스크 입출력은 CPU 속도에 비해 매우 느리기 때문에 입출력 요청의 처리가 완료되기 전까지 스레드 1은 앞으로 나아갈 수 없음
  • 쓰레드 1의 실행은 일시 중지 되고 CPU가 준비 완료 상태인 다른 스레드(스레드 2)에 할당됨
  • 스레드 2가 실행되고, 스레드 1의 디스크 입출력 요청 처리가 완료되면 CPU는 스레드 1을 이어서 실행

6.2.1 장치 제어기

  • 디스크와 같은 입출력 장치는 대체로 기계 부분과 전자 부분으로 나눌 수 있음

기계 부분

출처: https://babytiger.netlify.app/posts/hdd/

  • 플래터(Platter): 실질적으로 데이터가 저장되는 곳, 동그란 원판 모양
  • 스핀들(Spindle): 플래터를 회전시키는 구성요소
  • 헤드(R/W Head): 플래터 위에 미세하게 떠있어 데이터를 읽고 씀
  • Actuator Arm:헤드를 원하는 위치로 이동시킴

입출력 요청이 왔을 때 헤드를 통해 데이터를 읽고 쓰는데 데이터가 헤드가 위치한 트랙에 없을 가능성이 있음

  • 트랙: 플래터를 동심원으로 나누었을 때 그중 하나의 원
  • 이때 헤드가 특정 트랙으로 이동해야 하는데 이 과정을 탐색(seek)이라고 하며 매우 많은 시간이 소모
 

전자 부분

  • 전자 부품으로 구성되어 장치 제어기(device controller)라고 함
  • 자체적인 프로세서와 펌웨어, 버퍼, 레지스터를 갖추고 있어 CPU가 직접 도와주지 않는 상황에서도 복잡한 작업을 할 수 있음
  • 장치드라이버(device driver): 운영체제에 속한 코드인데 반해, 장치 제어기는 장치 드라이버에서 명령을 받아 외부 장치를 제어하는 하드웨어

⇒ 장치 제어기는 운영 체제에 해당하는 장치 드라이버와 외부 장치를 연결하는 다리에 해당

 

6.2.2 CPU가 직접 데이터를 복사해야 할까?

  • 디스크에서 자체 버퍼로 데이터를 읽었다면, 이후 CPU는 직접 데이터 전송 명령어를 실행하여 장치 제어기 버퍼에 있는 데이터를 따로 메모리로 복사해야 할까? 그렇지 않음

  • CPU 개입이 없는 상황에서 직접 장치와 메모리 사이에 데이터를 전송할 수 있는 작동방식을 직접 메모리 접근(direct memory access, DMA)라고 부름

 

6.2.3 직접 메모리 접근

  • CPU가 관여하지 않고, 메모리와 외부 장치 사이에서 데이터를 이동시키는 역할을 하는 것이 직접 메모리 접근
  • CPU가 직접 데이터를 복사하지 않지만, 반드시 어떻게 데이터를 복사할지 알려주는 명령어를 DMA에 전달해야 함
  • DMA는 bus arbitration, 즉 버스 사용권한을 요청한 후 장치를 작동시킴
  • 디스크에서 데이터를 읽을 때 장치 제어기의 버퍼에서 데이터를 읽으면 DMA가 지정된 메모리 주소에 데이터를 쓰는 방식으로 데이터 복사가 완료됨
  • DMA가 데이터 전송을 완료하면 인터럽트 작동 방식을 사용하여 CPU에 알려줌

 

6.2.4 전 과정 정리

스레드 1, 2가 있다고 가정

  • CPU로 실행되는 스레드 1이 시스템 호출로 입출력 요청을 시작하면, 운영 체제는 스레드 1의 실행을 일시 중지하고 CPU를 스레드 2에 할당 후 실행됨
  • 디스크가 동작하여 데이터 준비가 되면, DMA 작동 방식이 직접 장치와 메모리 사이에서 데이터를 전송
  • 데이터 전송이 완료되면 인터럽트 작동 방식을 이용하여 CPU에 알리고 CPU는 스레드 2를 중지 후 스레드 1이 다시 실행

⇒ 핵심은 디스크가 입출력 요청을 처리할 때 CPU가 그 자리에서 기다리지 않고 운영 체제의 스케쥴링에 따라 다른 스레드를 실행한다는 것

반응형
반응형

이 글은  컴퓨터 밑바닥의 비밀 chapter 6.1의 내용을 읽고 요약한 글입니다. 

 

6.1.5 배달 음식 주문과 중단 처리

  • 배달 음식을 주문 후 즐겁게 게임을 한다고 가정
  • 게임 중 배달 음식이 도착하면 게임을 일시 중지한 후 배달 음식을 받고 자리로 돌아와 게임을 이어할 수 있음 → 인터럽트 처리 과정

 

컴퓨터 시스템에서 기초적인 인터럽트 처리 구조

 
  • CPU가 특정 프로세스(프로세스 A)의 기계 명령어를 실행할 때 새로운 이벤트가 발생
    • 네트워크 카드에 새로운 데이터가 들어오면 외부 장치가 인터럽트 신호를 보내고
    • CPU는 실행 중인 현재 작업의 우선순위가 인터럽트 요청보다 높은지 판단
    • 인터럽트의 우선순위가 더 높다면 현재 작업 실행으 일시 중지하고 인터럽트를 처리하고 다시 현재 작업으로 돌아옴
  • 프로그램은 계속 끊임없이 실행되는 것이 아니라 언제든지 장치에 의해 실행이 중단될 수 있음
  • 하지만 이 과정은 프로그래머에게 드러나지 않으며 중단 없이 실행되고 있는 것처럼 느끼게 만듦

 

6.1.6. 인터럽트 구동식 입출력

인터럽트 발생 시 CPU가 실행하는 명령어 흐름

프로그램 A의 기계 명령어 n 실행
프로그램 A의 기계 명령어 n + 1 실행
프로그램 A의 기계 명령어 n + 2 실행
프로그램 A의 기계 명령어 n + 3 실행
인터럽트 신호 감지
프로그램 A의 실행 상태 저장
인터럽트 처리 기계 명령어 m 실행
인터럽트 처리 기계 명령어 m + 1 실행
인터럽트 처리 기계 명령어 m + 2 실행
인터럽트 처리 기계 명령어 m + 3 실행
프로그램 A의 실행 상태 복원
프로그램 A의 기계 명령어 n + 4 실행
프로그램 A의 기계 명령어 n + 5 실행
프로그램 A의 기계 명령어 n + 6 실행
프로그램 A의 기계 명령어 n + 7 실행
  • 폴링 방식보다 효율적으로 시간을 낭비하지 않음
    • 실제는 약간의 시간을 낭비하는데 주로 프로그램 A의 실행 상태를 저장하고 복원하는데 사용

프로그램 A의 관점에서 CPU가 실행하는 명령어 흐름은 아래와 같음

프로그램 A의 기계 명령어 n 실행
프로그램 A의 기계 명령어 n + 1 실행
프로그램 A의 기계 명령어 n + 2 실행
프로그램 A의 기계 명령어 n + 3 실행
프로그램 A의 기계 명령어 n + 4 실행
프로그램 A의 기계 명령어 n + 5 실행
프로그램 A의 기계 명령어 n + 6 실행
프로그램 A의 기계 명령어 n + 7 실행
  • CPU는 마치 중단된 적이 없는 것처럼 자신의 명령어를 계속 실행 → 프로그램 A의 실행 상태를 저장하고 복원하는 작업이 필요한 이유로 입출력을 비동기로 처리하는 방법을 인터럽트 구동식 입출력이라고 함 (interrupt driven input and output)

6.1.7 CPU는 어떻게 인터럽트 신호를 감지할까?

CPU가 기계 명령어를 실행하는 과정

  • 명령어 인출(instruction fetch)
  • 명령어 해독(instruction decode)
  • 실행(execute)
  • 다시 쓰기(write back)
  • CPU가 하드웨어의 인터럽트 신호를 감지하는 단계

인터럽트 신호가 발생하면 이 이벤트를 처리할지 여부를 반드시 결정해야 함

6.1.8 인터럽트 처리와 함수 호출의 차이

  • 함수를 호출하기 이전에 반환 주소, 일부 범용 레지스터의 값, 매개변수 등 정보 저장이 필요
  • 인터럽트 처리 점프는 서로 다른 두 실행 흐름을 포함하므로 함수 호출에 비해 저장해야 할 정보가 훨씬 많음

6.1.9 중단된 프로그램의 실행 상태 저장과 복원

 

  • 프로그램 A가 실행 중일 때 인터럽트가 발생하면 A의 실행은 중단되고, CPU는 인터럽트 처리 프로그램(interrupt handler) B로 점프
  • CPU가 인터럽트 처리 프로그램 B를 실행할 때 다시 인터럽트가 발생하면 B는 중단되고 CPU는 인터럽트 처리 프로그램 C로 점프
  • CPU가 인터럽트 처리 프로그램 C를 실행할 때 도 다시 인터럽트가 발생하면 C의 실행은 중단되고 CPU는 인터럽트 처리 프로그램 D로 점프
  • D의 실행이 완료되면 프로그램 C, B, A 순서대로 반환됨

상태 저장 순서

  1. 프로그램 A의 상태 저장
  2. 프로그램 B의 상태 저장
  3. 프로그램 C의 상태 저장

상태 복원 순서

  1. 프로그램 C의 상태 복원
  2. 프로그램 B의 상태 복원
  3. 프로그램 A의 상태 복원

상태가 먼저 저장될수록 상태 복원은 더 나중에 됨 → 스택를 사용해 구현하고, 스택에는 다음 기계 명령어 주소와 프로그램의 상태가 저장됨

 

 

반응형

+ Recent posts