2020-11-23 에 겪었던 나의 시행착오

다른곳에 저장해두었던 내용을 블로그에 옮겨본다.

 

-v 옵션을 처음 봤을 당시, 보고 문득 혼자 상상의 나래를 펼치며 망상을 했었다...

공부하다가 이해가 안가는 부분을 여기저기 물어보다 깨닫게 되곤한다.

게다가 물어보면 정말 검증 방법까지 알려주시는 감사한 현업자 선배님들...

 

 

Docker Container Volume

필요한 이유

  • container가 run 명령에 의해 시작될 때는 read-only image로부터 시작되어 container의 filesystem은 read-only layer 위에 read-write layer로 만들어진 virtual filesystem 이다.
  • 실제 Container를 시작한 후 만들어진 파일은 persistent filesystem에 저장된 것처럼 느껴지지만, 실제로는 디스크에 쓰여지는 것이 아니라 in-memory file system 에 쓰이는 것이므로, container가 종료되면 사라진다.
  • 동일한 image로부터 container를 다시 만들면, 저장한 데이터는 사라지게 된다.
  • 만약 DB를 사용하는 앱이라면, DB에 record 를 저장하였으나, container 가 종료되면 DB 테이블이 사라지게 된다.

⇒ 이러한 문제를 해결하기 위해 Container Volume을 제공

  • -v 옵션을 사용해 docker run할 때 이미지만 변경하고 같은 볼륨을 마운트 하는 식으로 사용한다.

Docker Volume 설명

  • -v <host path> : <mounting point path in container>
  • volume 을 mount 하여 실제 디스크에 영구적으로 데이터를 저장하여, container가 종료되어도 영구적으로 데이터를 저장할 수 있다
  • but, 단점도 있다.
  • container의 장점 중의 하나는 container들 사이에 filesystem을 통한 간섭이 없어서 보안이 뛰어나다는 것인데 volume 기능은 잘못된 코딩 또는 바이러스에 의해 이러한 장점이 훼손될 수 있다.

Docker Volume 3가지 type

  1. Host volume
    • docker run -v /home/mount/data:/var/lib/mysql/data
    • 정확하게 mount할 경로를 지정
  2. named volume
    • docker run -v name:/var/lib/mysql/data
    • data 참조를 쉽게 하기 위해 이름으로 설정
  3. Anonymous volume
    • docker run -v /var/lib/mysql/data

 

 

 

 

 

동아리 현업 선배님들한테 항상 많은 도움을 받는다..

'Tech-Talk' 카테고리의 다른 글

TCP connection 과 Streaming + QUIC 에 대한 고찰  (0) 2021.08.29

같이 스터디하는 분들끼리 TCP connection에 대해 의견이 분분해서 토론이 시작되었고, 추가로 느꼈던 의문과 고민, 그 답을 찾아가는 과정을 남겨놓았습니다.

 

토론의 시작 질문

핸드폰으로 유튜브를 보던 중에 핸드폰의 IP가 변하면 TCP 연결이 끊어지나요?

 

상황 설명

  1. 와이파이에 연결되어 있다가 와이파이를 끊어서 Public IP가 바뀐다던가.
  2. 핸드폰을 들고 이동해서 IP가 바뀐다던가.

 

내 시나리오

TCP 연결이 끊어진다

 

서버사이드(유튜브)랑 클라이언트(핸드폰) 사이드로 나눠서 보면

  1. 둘이 TCP 연결되어있다가 클라이언트 IP가 변경되면 서버에서는 그걸 모른다.
  2. 따라서 서버에서는 계속해서 클라이언트에게 응답 패킷을 보낸다
  3. 근데 클라이언트는 그걸 못받는다. 왜? 기존 연결되어있던 IP가 바뀌었으므로
  4. 클라이언트는 바뀐 새 source ip로 TCP 연결되어있듯이 계속 서버에게 요청을 보낸다
  5. 서버는 TIME_OUT으로 기존 ip(라우터)와 연결이 끊긴다.
  6. 클라이언트도 계속해서 요청을 보냈는데 서버의 응답을 못 받아서 TIME_OUT으로 연결이 끊긴다.
  7. 연결이 끊겼으니 클라이언트가 TCP 연결을 다시 시도한다.
  8. 새로운 TCP 연결이 생긴다.

 

다른 분 시나리오

TCP 연결이 끊어 지지 않는다.
  1. 계층화의 개념으로 생각해보면 TCP 연결은 port만으로 연결이 되기 때문에 IP는 상관이 없다.
  2. Transport(전송) 계층 패킷의 헤더를 생각해보면 Source Port, Destination Port 만 있지 않은가?
  3. TCP는 전송계층 프로토콜 이므로, IP가 바뀌어도 TCP 연결이 끊기지는 않는다.

 

첫 번째 결론

일단 토론 끝에 내린 결론은

  • TCP 연결하는 통신에서도 패킷의 <소스 IP, 소스 port, 타깃 IP, 타깃 port>를 TCP control block으로 사용하기 때문에, 소스 IP가 변경되면 재 연결된다.

입니다!

 

 

추가 문제

TCP 연결이 끊어지느냐에 대한 것은 YES로 결론이 났다. 하지만 여기서 문제가 하나 더 있었으니,

유튜브는 스트리밍이므로 TCP 통신이 맞는가 UDP 통신이 맞는가?

우선 이론적으로 배운것을 바탕으로 시나리오를 작성해보고, 다른 개발자분들과 이야기를 나눠보며 새로 생긴 이슈들이다.

 

1. TCP는 신뢰성을 보장하기 위한 연결 지향 프로토콜이다 보니 흐름 제어나 혼잡 제어 등을 해서 속도가 느린 반면, UDP는 비연결성 프로토콜로 속도가 빨라서 보통 실시간 스트리밍 같은 곳에 많이 쓰인다.

 

2. 따라서 실시간 스트리밍 서비스는 UDP일 것이다.

 

3. 그러나, 유튜브 컨텐츠를 보는 것이 리얼타임 통신은 아니지 않은가?

 

4. 그렇다면 굳이 UDP를 쓸 이유도 없어진다.

 

5. 그럼 TCP인가?? 

 

6. 또한 HTTP 는 TCP/IP 기반 응용 프로토콜이다.

 

7. 브라우저는 UDP를 지원하는가..?

 

등의 끊이지 않는 의문이 생겼다.

 

이 의문들을 당장 해결하기 위해서, 바로 유튜브를 켜고, 개발자 도구를 열어서, 당장 Response Header를 살펴보았다.

유튜브 컨텐츠의 HTTP 헤더

그랬더니 예상과는 전혀 다른 quic라는 프로토콜이 튀어나오는 것이었다....!!

 

여기서 멈출 수는 없었다.

 

그렇게 quic 에 대해 알아보았다.

 

 

QUIC (Quick UDP Internet Connections)

QUIC 프로토콜은 Google에서 개발된 프로토콜로 현재 표준 등록을 진행 중이라고 한다.

우선 UDP 위에 QUIC 프로토콜은 얹고 HTTP를 얹은 게 눈에 띈다.

거기에 TCP-like 혼잡 제어 + loss recovery 라니...

 

간단하게,

UDP로 3-way-handshake 없애서 속도 올리고, QUIC로 TCP-like 신뢰성을 추가한다 라는 소리로 들린다.

 

즉, UDP의 속도적 장점 + TCP의 신뢰성 장점을 합친 것이 이 프로토콜의 목표인 것 같다.

 

 

TCP vs QUIC

 

시간적 이점이 왜 나타나는지를 조금 더 자세히 살펴보자.

 

TCP + TLS에서 동작하는 HTTP/2 프로토콜에는 HOL(head-of-line) 문제가 있었다.

  • HOL(head-of-line): HTTP/2에서 TCP 연결을 통해 패킷 전송이 일어날 때, 한 패킷에 문제가 생기면 다른 패킷 전송이 영향이 간다.

이에 QUIC는 독립 스트림을 여러 개 만들어 이 문제를 피하고자 하는 것이 핵심이다.

또한 hanshake 과정의 시간도 비교가 안된다.

 

 

 

결론

1. TCP 연결이 되어있다가 Client IP (Source IP)가 바뀌게되면 TCP control block으로 사용하는 패킷의 <소스 IP, 소스 port, 타깃 IP, 타깃 port>가 바뀌므로 TCP connection 이 끊기고 재연결된다.

 

2. 유튜브 스트리밍 서비스는 UDP 기반 QUIC 프로토콜을 이용한다.

 

여담

구글의 대부분의 제품에는 이미 quic 가 들어가 있지만, 아직 표준이 지정되지 않았고 UDP 기반의 프로토콜을 서버가 받아들이는 데 있어서 최적화나 검증되지 않은 부분이 많기 때문에 항상 속도가 더 빠르다고 장담할 수는 없다.

 

다만, 표준이 지정되고 시대가 HTTP/3로 넘어가게 되면 IE의 몰락처럼, TCP 기반이 아닌 UDP 기반의 QUIC를 당연히 사용하는 시대가 올 수 있지 않을까.

(기술은 늘 변하는 것이고, 문제를 해결하는 데 있어서 더 좋은 해결책이 나왔다면 자연스레 바뀌기 마련이라 생각한다..)

 

 

 

 

이 내용들은 제가 공부하며 느꼈던 의문과 고민, 그 답을 나름대로 찾아가는 내용입니다.

아직 많이 부족하니. 틀린 부분은 얼마든지 지적해주세요!

 

 

Reference

 

언제나 즐거운 질문과 답변에서 이어지는 티키타카

1. 개발자 커뮤니티에 질문


2. 같은 동아리 출신 개발자 분들께 질문

 

'Tech-Talk' 카테고리의 다른 글

Docker -v 옵션에 대한 혼돈과 깨달음  (2) 2021.08.29

1. 동시성 제어 (Concurrency Control)

  • Context-Switch : CPU에서 running 중이던 process를 PCB에 store 하고, 다른 PCB의 register 정보(PC, IR)를 CPU에 load 해오는 상황
  • Concurrency-Control : Context-Switch 를 통해서 time-sharing을 함. 즉, 동시성 = 시분할

 

2. Concurrent vs Parallel

  • Concurrenct : 시분할
  • Parallel : multicore에서 실제 동시에 병렬적으로 실행 Parallelism
    1. data parallelism
    2. task parallelism

 

3. 동기(synchronous) vs 비동기(asynchronous) / blocking vs non-blocking

  • Synchronous VS Asynchronous
    • 두 가지 이상의 대상(메서드, 작업, 처리 등)과 이를 처리하는 시간으로 구분한다.
    • Synchronous
      • 호출된 함수의 리턴하는 시간과 결과를 반환하는 시간이 일치하는 경우
      • 함수의 결과를 호출한 쪽에서 처리
    • Asynchronous
      • 호출된 함수의 리턴하는 시간과 결과를 반환하는 시간이 일치하지 않는 경우
      • 함수의 결과를 호출한 쪽에서 처리하지 않는다.
      • 호출되는 함수에게 callback을 전달해서, 호출되는 함수가 전달받은 callback을 실행
  • Blocking VS Non-Blocking
    • 호출되는 대상이 직접 제어할 수 없는 경우 이를 구분할 수 있다.
    • Blocking: 호출된 함수가 자신의 작업을 모두 마칠 때까지 호출한 함수를 기다리게 만든다.
    • Non-Blocking: 호출된 함수가 바로 리턴해서 호출한 함수에게 제어권을 준다.

 

4. 동기화 객체의 종류

  • 스레드 동기화 방법
    1. 실행 순서의 동기화
      • 스레드의 실행 순서를 정의하고, 이 순서에 반드시 따르도록 하는 것
    2. 메모리 접근에 대한 동기화
      • 메모리 접근에 있어서 동시 접근을 막는 것
      • 실행의 순서가 중요한 상황이 아니고, 한 순간에 하나의 스레드만 접근하면 되는 상황을 의미
  • 동기화 기법의 종류
    1. 유저 모드 동기화
      • 커널의 힘을 빌리지 않는(커널 코드가 실행되지 않는) 동기화 기법
      • 성능상 이점, 기능상의 제한
      • Ex) 크리티컬 섹션 기반의 동기화, 인터락 함수 기반의 동기화
    2. 커널 모드 동기화
      • 커널에서 제공하는 동기화 기능을 활용하는 방법
      • 커널 모드로의 변경이 필요하고 이는 성능 저하로 이어짐, 다양한 기능 활용 가능
      • Ex) 뮤 텍스 기반의 동기화, 세마포어 기반의 동기화, 이름있는 뮤텍스 기반의 프로세스 동기화, 이벤트 기반의 동기화

 

 

5. 동기화 관련 문제들

  1. busy-waitingsleep and wakeup으로 해결
  2. 생산자 소비자 문제 (Producer-Consumer)
    • 생산자 (producer) : 버퍼에 정보를 삽입
    • 소비자 (consumer) : 버퍼에서 정보를 제거
    • 버퍼가 가득 차 있다면? 생산자를 sleep --> 소비자 수행 후, wakeup
    • count에 대한 접근 → Race-Condition (경쟁 조건) → wakeup signal 분실 가능
    • 해결 : 세마포어 활용
  3. 식사하는 철학자들 문제
    • 철학자는 스파게티를 먹기 위해 양옆의 포크를 동시에 들어야 한다.
    • 이때, 전부 왼쪽 포크를 먼저 들면, 오른쪽 포크를 전부 못 들어 무한정 기다리게 된다.
    • 즉, 제한된 수의 자원에 접근하는 문제
    • 동시성 + 데드락 : 여러 프로세스가 동시에 돌아갈 때 교착 상태에 빠지는 원인
    • 해결 : 동시성을 제거 - 필요한 포크가 사용 중이라면, 배고픈 철학자라도 블락된다
  4. 독자 저자 문제 (The Readers and Writers Problem)
    • 식사하는 철학자 문제가 I/O와 같이 제한된 수의 자원에 접근하는 문제라면
    • 읽는 자 쓰는 자는 데이터베이스에 접근하는 모델
    • 여러 리더가 존재 가능
    • Reader와 Writer의 배타적 접근
    • 해결 : 뮤 텍스 세마포어
  5. 잠자는 이발사 문제
    • 한 명의 이발사, 하나의 이발용 의자, 기다리는 손님을 위한 n개의 의자
    • 손님이 없으면 이발사는 sleep
    • 손님이 오면 이발사는 wakeup
    • 이발 중 손님이 오면 대기용 의자에서 기다림
    • 대기용 의자도 만석이면 손님은 그냥 이발소를 떠남
    • ⇒ 이발사와 손님이 Race-Condition에 빠지지 않도록 하는 것
    • 해결 : 뮤 텍스
      • 한 번에 한 명만이 동작 상태를 바꿀 수 있게 한다.
      • 이발사 : 뮤 텍스 얻어야 대기실 손님 확인 가능
      • 손님 : 뮤텍스 얻어야 이발소 들어갈 수 있음, 대기실 or 의자에 앉으면 뮤텍스 반납
    • 복수의 잠자는 이발사 문제 : 세마포어 필요

 

6. Critical Section (임계 영역)

  • 멀티 스레딩에 문제점에서 나오듯, 동일한 자원을 동시에 접근하는 작업을 실행하는 코드 영역
  • Race Condition을 유발하는 코드 블록
  • (e.g. 공유하는 변수 사용, 동일 파일을 사용하는 등)

 

7. Race Condition 이란?

  • 공유 자원에 대해 여러 프로세스/스레드가 동시에 접근을 시도하는 상황
  • 즉, 하나의 자원을 두고 경쟁하는
  • 타이밍에 따라서 결과가 다를 수 있어, 자료의 일관성을 해치는 결과가 나타남
  • ex) 은행에서 출금하는 스레드 사이에서 발생하는 경우 balance가 덜 줄어듦 → 심각한 문제
    1.  

 

8. Race Condition이 발생하는 경우

  • Shared resource에 access 했는데 동기화를 하지 않으면 발생
  1. 커널 작업을 수행하는 중에 인터럽트 발생
    • 문제점 : 커널 모드에서 데이터를 로드하여 작업을 수행하다가 인터럽트가 발생하여 같은 데이터를 조작하는 경우
    • 해결법 : 커널 모드에서 작업을 수행하는 동안, 인터럽트를 disable 시켜 CPU 제어권을 가져가지 못하도록 한다.
  2. 프로세스가 'System Call'을 하여 커널 모드로 진입하여 작업을 수행하는 도중 문맥 교환이 발생할 때
    • 문제점 : 프로세스 1이 커널 모드에서 데이터를 조작하는 도중, 시간이 초과되어 CPU 제어권이 프로세스2로 넘어가 같은 데이터를 조작하는 경우 ( 프로세스2가 작업에 반영되지 않음 )
    • 해결법 : 프로세스가 커널모드에서 작업을 하는 경우 시간이 초과되어도 CPU 제어권이 다른 프로세스에게 넘어가지 않도록 함
  3. 멀티 프로세서 환경에서 공유 메모리 내의 커널 데이터에 접근할 때
    • 문제점 : 멀티 프로세서 환경에서 2개의 CPU가 동시에 커널 내부의 공유 데이터에 접근하여 조작하는 경우
    • 해결법 : 커널 내부에 있는 각 공유 데이터에 접근할 때마다, 그 데이터에 대한 lock/unlock을 하는 방법

 

9. Thread-safe 의미, 구현

  • 의미
    • 멀티스레드 환경에서 여러 스레드가 동시에 하나의 객체 및 변수(공유 자원)에 접근할 때, 의도한 대로 동작하는 것
  • 구현
    • 결국 동기화
    • 2개의 critical regionmutual exclusive 하게 수행되도록 막아서, 2개의 thread를 synchronize 하면 Race-condition을 없앨 수 있다.

 

10. Critical Section Problem (임계 영역 문제)를해결하기 위한 조건

  1. 상호 배제 (Mutual Exclusion) : 한 프로세스가 임계 구역에 들어가 있으면 다른 프로세스 들어갈 수 없다.
  2. 진행 (Progress) : 임계구역에 들어간 프로세스 없다면 어느 프로세스가 들어갈지 적절히 선택
  3. 한정 대기 (Bounded Waiting) : 기아 방지를 위해 한 번 들어갔다 나온 프로세스는 다음에 들어갈 때 제한을 준다. - no Starvation

(+) CPU의 속도 등에 대한 어떠한 가정도 하면 안 된다

 

 

11. Mutex (Mutual Exclusive), 상호 배제

  • Mutual exclusive 하게 수행하도록 하여 synchronize 하는 것
  • 그러므로 Race Condition을 없앤다.
  • 화장실이 하나뿐인 식당, 열쇠 1개
  • 여러 프로세스/스레드가 공유된 자원에 접근하는 것을 막는 것
  • 여러 프로세스가 공유 자원 사용하려 할 때 번갈아 가며 사용하도록 함
  • 임계 구역 내에서 인터럽트, 교착상태, 무한반복 발생하지 않도록 해야 함
  • 키가 1개인 세마포어라고 볼 수 있다. (이진 세마포어)
  • 구현 방법
    • 2개 프로세스 기준 : 데커 알고리즘, 피터슨 알고리즘
    • 여러 개 프로세스 기준 : Lamport의 빵집 알고리즘

 

 

12. Critical Section Problem 해결 방법 4가지

  1. Lock
  2. Semaphore
  3. Monitor
  4. Message

 

13. Lock

  • 자원을 사용하는 동안 들어오지 못하도록 잠구는 것
  • 하나의 자원에 여러 스레드가 동시에 접근하는 것을 조율해준다.

1) 기본형

  • 동시에 공유 자원에 접근하는 것을 막기 위해 Critical Section에 진입하는 프로세스는 Lock을 획득하고 Critical Section 을 빠져나올 때, Lock 을 방출함으로써 동시에 접근이 되지 않도록 한다.
while (lock == 1);
lock = 1;
Critical_region();
lock = 0;
  • 한계 : lock 이 0 일 때 두 스레드가 동시에 진입하면 문제!

2) Spin Lock

  • busy waiting을 사용한 lock
  • 장점 : lock이 해제될 때 context-switching 이 없어서, 오버헤드 없이 critical section 접근 가능
  • 단점 : 어떤 스레드가 락을 오래 소유하면, CPU 낭비
  • 한계 : Progress를 만족하지 않음 - 010101 번갈아서 들어와야 함 / 000 이면 실행 안됨
  • 언제 사용? 멀티-스레드에서 critical section 이 아주 작거나, 빠른 처리 가능할 때
while(True) {
	while (turn != 0);
	Critical_region();
	turn = 1;
	Noncritical_region();
}

 

while(True) {
	while (turn != 1);
	Critical_region();
	turn = 0;
	Noncritical_region();
}

 

3) Peterson's Solution

  • 소프트웨어적으로 이 방법을 쓰면 해결 가능하지만, 오버헤드가 크다

4) TSL (Test and Set Lock) instruction

  • 하드웨어적으로 제공되는 명령어로 atomic 하게 실행된다.
# 하드웨어에서 이런 명령어를 제공
bool Test_and_Set(bool *flag) {
	bool old = *flag;
	*flag = True;
	return old;
}

lock = false;
repeat
	while Test_and_Set(lock) do no-op;
	Critical Section
	lock = false;
	Remainder Section
until false
  • 문제
    • Spin Lock 이기 때문에 CPU를 계속 써야 함 (Lock 값 계속 체크해야 함)

 

 

14. Sleep and Wakeup

  • busy-waiting 해결 → 임계 구역 진입이 허용되지 않을 때, CPU 시간을 낭비하는 대신 블록 하는 프로세스 간 통신 고려
    • sleep : 호출자를 block → 다른 프로세스가 깨울 때 (wakeup)까지 보류
    • wakeup
  • 발생 문제 : 생산자 - 소비자 문제 (한정된 버퍼 문제)
    • 생산자 (producer) : 버퍼에 정보를 삽입
    • 소비자 (consumer) : 버퍼에서 정보를 제거
    • 버퍼가 가득 차 있다면? 생산자를 sleep --> 소비자 수행 후, wakeup

 

 

15. Semaphore

  • 화장실이 여러 개 있는 레스토랑, 열쇠 = 칸 개수만
  • 현재 공유자원에 접근할 수 있는 프로세스/스레드 수를 나타내는 값을 두어 상호 배제
  • Lock시 특정 수만큼의 카운트를 더하고
  • Unlock시 빼주는 형식으로 처리
  • 이런 락을 슬립( Sleep ) 가능한 락이라고 함
  • Up, Down은 atomic 하게 동작
  • 생산자 소비자 문제의 근본적 해결
  • 동기화해야 하는 대상이 여러 개일 때 사용

1) 카운팅 세마포어

  • 가용한 개수를 가진 자원에 대한 접근 제어용으로 사용되며, 세마포는 그 가용한 자원의 개수로 초기화된다. 자원을 사용하면 세마포가 감소, 방출하면 세마포가 증가한다.
  • 생산자 소비자 문제와 비교하기
  • count 하나로 표현되던 부분들이 up, down을 이용하여 mutex, empty, full로 표현
#define N 100   // 버퍼 용량
int mutex = 1;  // 공유 데이터를 위한 mutex
int empty = n   // 빈 용량
int full = 0    // 찬 용량

void producer(void) {
	int item;

	while(TRUE) {
		item = produce_item();  // item 생성
		down(&empty);           // if 꽉차지 않았으면 empty--;
		down(&mutex);           // mutex = 0 으로 해서, lock 처리
		insert_item(item);      // 버퍼에 추가
		up(&mutex);             // mutex = 1 으로 해서, unlock 처리
		up(&full);
	}
}

void consumer(void) {
	int item;

	while(TRUE) {
		down(&full);
		down(&mutex);
		item = remove_item();  // 
		up(&mutex);
		up(&empty);
		consume_item(item);  
	}
}

2) 이진 세마포어 (MUTEX)

  • MUTEX라고도 부르며, 상호 배제의 (Mutual Exclusion)의 머릿글자를 따서 만들어졌다. 이름 그대로 0과 1 사이의 값만 가능하며, 다중 프로세스들 사이의 Critical Section 문제를 해결하기 위해 사용한다.

 

16. Monitor

  • 동기화를 구현하기 위한 특수 프로그램 기법
  • 특정 공유 자원을 프로세스에게 할당하는 데 필요한 데이터와 이 데이터를 처리하는 프로시저로 구성
  • 자료 추상화, 정보 은폐 개념을 기초, 병행성 구조
  • 상호 배제가 low-level 단에서 지원됨
  • → "단 하나의 프로세스만 한 순간에 모니터에서 활동할 수 있다."
  • 생산자-소비자 문제 해결
    • 조건 변수 wait, signal 도입
    • sleep, wakeup과 달리 모니터에서는 자동적으로 상호 배제가 됨→ 문맥교환 될 걱정하지않고 연산 완료 가능
    • → wait, signal은 상호배제가 아님

 

17. Message Passing

  • send / receive ; 시스템 호출 일종
  • acknowledgement 분실 문제 -> 메시지 구별 필요
  • 인증 --> 프로세스의 유일성 보장
  • 생산자 - 소비자 문제
    • 공유 메모리가 아닌, 메시지 전달로 해결
    • 가정
      1. 모든 메시지는 동일한 크기
      2. 메시지는 운영체제에 의해 자동 버퍼링
    • 방법
      1. 소비자는 시작할 때, N개의 빈 메시지를 생산자에게 보냄
      2. 생산자는 소비자에게 전달할 아이템을 생산하면, 빈 메시지 수신 → 아이템이 들어 있는 메시지 전송

'CS > 운영체제 (OS)' 카테고리의 다른 글

8. IPC (Inter-Process Communication)  (0) 2021.08.11
7. 프로세스 vs 스레드  (0) 2021.08.11
4. 프로세스의 주소 공간  (1) 2021.08.08
3. 인터럽트 (Interrupt)  (1) 2021.08.08
2. 커널 (Kernel)  (0) 2021.08.06

1. IPC (Inter-Process Communication)

프로세스 간 통신하는 방법 2가지

1) 공유 메모리 사용 (Shared-Memory)

  • 버퍼를 shared-memory로 만들면 된다 → Shared Buffer
  • 생산자 - Buffer - 소비자
  • buffer 가득차면 Producer: waiting / buffer 비면 Consumer: waiting
  • 문제 상황
    • 성능이 좋지만 동기화 문제 발생
    • 응용 프로그래머가 다 해결해야 함 → 너무 복잡
  • 문제 해결 : Message-Passing 으로!!

2) Message-Passing

  • send(message), receive(message) system call로 OS가 해결
  • ex. pipes
  • communication link를 구현

 

2. Message-Passing

direct vs indirect

1) direct

  • send(P, message) - p에게 메시지 전송, receive(Q, message) - Q로부터 메시지 수신
  • 링크가 automatically 생성됨
  • 2개의 프로세스 간에 정확히 하나의 링크만 만들어짐 (1 : 1)

2) indirect

  • 뭔가 매개체가 필요함 - 매개체 = Port (mailbox)
  • 그냥 port로 전송만 하면 됨
  • 복잡한 Communication link를 만들 수 있음 (다 : 다)
  • 여기서 또 blocking I/O vs non-blocking I/O으로 나누어짐

 

3. 실제 IPC 예시

1) Shared Memory : POSIX Shared Memory

  • POSIX: Portable OS Interface (for UNIX)
  • memory-mapped files 사용
  • 문제 : 일일이 shm_open, write, read, close 등을 프로그래머가 다 해줘야 함
  • 좀 더 진화된 형태 : pipes

2) Message Passing : Pipes

  • 생산자-소비자 방식으로 두 개의 프로세스가 서로 통신하는 메커니즘
  • uni-direction (단방향) vs bi-direction(양방향)
  • half-duplex(송, 수신 중 한 번에 하나만 가능) vs full-duplex (양방향으로 동시에 송수신)
  • 전통적인 pipe = 단방향 통신 2개 만들어 양방향처럼 사용하면 됨
  • 문제 : 그럼 Client-Server System에서는??
    • 네트워크 내에서 다른 2개의 컴퓨터끼리 shared memory 및 pipe 연결 불가능!!
  • 해결 : socket

 

4. Communication in Client-Server Systems

Pipe → Socket → RPC

1) Sockets

  • IP addr + Port = Socket
  • 네트워크 상의 서로 다른 endpoint 끼리의 통신할 때
  • Java
    • Socket class: connection-oriented (TCP)
    • DatagramSOcket class: connectionless (UDP)
    • MulticastSocket class: multiple recipients

2. RPCs (Remote Procedure Calls)

  • remote host에 있는 procedure를 호출하겠다.
  • marshaling 한 파라미터를 서로 넘겨줌 (쉽게, server, client 간에 넘겨줄 parameter 형식 맞춰준다고 생각)
    ex. serialization
  • IPC의 확장 개념

 

 

1. 스레드란?

  • 프로세스가 할당받은 자원을 이용하는 실행 흐름의 단위.
  • 공유 자원 : 주소 공간, Code, Data, Heap, 열린 파일, 신호
  • 별도 자원 : register와 Stack
  • 자원의 생성과 관리의 중복성을 최소화하여 수행 능력을 향상
  • 한 스레드의 결과가 다른 스레드에 영향을 끼친다.

User-level thread

  • 장점 : 빠르다
  • system call이나 I/O 가 발생해서 Block 되면, 프로세스 자체가 block 되었다고 판단하여, 다른 스레드도 돌릴 수 없다. → CPU 안 쓰게 된다.
  • 무한 루프 돌고 있어서 자원을 계속 차지하고 있어도, 뺏어올 수 없음 → 자발적으로 넘겨줘야 함

Kernel-level thread

  • 단점 : 느리다.
  • OS 가 알아서 thread 가 block 되면 다른 thread로 CPU를 할당함

 

2. 멀티 스레드

  • 멀티 스레드를 제공한다면, CPU를 점유하는 가장 작은 단위 = 스레드가 됨
  • 즉, Parallel 한 작업
  • 한 개의 단일 애플리케이션은 여러 스레드로 구성 후 작업 처리해야 한다.
  • 한글에서 싱글 스레드를 사용하면, 프린트를 하는 경우 문서 수정은 불가능하다.
  • 디버깅이 어렵다. 자원 공유 문제(교착상태)가 생긴다.

우리가 컴퓨터 살 때 보는 '6 코어 12 스레드'에서 스레드는 물리적인 코어 6개로 12개의 스레드를 동시 멀티스레딩(SMT, Simultaneous Multi-Threading)으로 구현이 된 것이라고 한다 (하이퍼스레딩이 있는 CPU라고 한다). 즉 S/W의 관점으로는 하나의 코어에 하나의 가상의 코어를 만들어서 CPU 2개로 인식된다. 

 

즉, 물리적인 Core 위에 하이퍼스레딩으로 구현된 (물리적이라고 볼 수 있는) Core 스레드가 여러 개 존재하고, 그 위로 Kernel-level 스레드가 더 여러개 있을 수 있고, 그 위로는 User-level 스레드가 더더 여러개 있을 수 있는 구조가 되겠다. (물론 어떤 멀티 스레드 모델이냐에 따라 다를 수 있다.)

멀티 스레드 모델

 

 

3. Context-Switching : 프로세스 vs 스레드

  • 프로세스는 운영체제로부터 자원을 할당받아 실행하고, 스레드는 프로세스로부터 자원을 할당받아 실행합니다.
  • 프로세스 : fork()를 통해 생성되는데, 매번 동일한 코드가 복사되어 작동하고, PCB, 주소 복사 등 Context Switching에 Cost가 크다.
  • 스레드 : 레지스터와 스택을 제외하고 자원을 공유하여 사용 → 한 가지 스레드는 I/O를 담당하는 등, 스레드로 각 CPU에 일을 할당해서 수행 가능

 

 

4. 멀티 프로세스 vs 멀티 스레드

1. 멀티 프로세스

  • Concurrency 한 작업

 

2. 멀티 스레드

  1. 멀티 프로세스보다 자원을 효율적으로 사용 가능
    • 멀티 프로세스로 실행하던 작업을 멀티 스레드로 실행하면, 프로세스를 생성하여, 자원을 할당하는 시스템 콜이 줄어든다
    • 메모리를 공유하기 때문에, 프로세스 간 통신 방법에 비해 스레드 간의 통신 방법이 간단하다.
  2. 처리 비용 및 응답 시간 단축
    • context-switching 시 발생하는 오버헤드를 감소시킬 수 있다.
    • 심지어 스레드의 context switch는 프로세스 context switch 와는 달리 캐시 메모리를 비울 필요가 없다.
  3. 문제점
    • 멀티 프로세스 기반으로 프로그래밍할 때는 프로세스 간 공유하는 자원이 없기 때문에 동일한 자원에 동시에 접근하는 일이 없었지만 멀티 스레딩을 기반으로 프로그래밍할 때는 이 부분을 신경 써줘야 한다. 서로 다른 스레드가 데이터와 힙 영역을 공유하기 때문에 어떤 스레드가 다른 스레드에서 사용 중인 변수나 자료구조에 접근하여 엉뚱한 값을 읽어오거나 수정할 수 있다.
  4. 해결
    • 멀티스레딩 환경에서는 동기화 작업이 필요하다. 동기화를 통해 작업 처리 순서를 컨트롤하고 공유 자원에 대한 접근을 컨트롤하는 것이다. 하지만 이로 인해 병목현상이 발생하여 성능이 저하될 가능성이 높다. 그러므로 과도한 락으로 인한 병목현상을 줄여야 한다.

 

5. Thread 관련 예시

(질문1) 워드에서 글자를 입력했을 때 어떤 일이 발생하는가?

  • 사용자 입력 → 외부 Interrupt 중 I/O Interrupt 발생 → CPU 인지 → CPU 작업 중이던 상태 저장 → 해당 인터럽트 처리 → 상태 복구 및 중단되었던 작업 재개

개인적으론 이 질문이 크롬에 사이트 url을 입력했을 때 일어나는 일을 설명해보라는 질문과 동급이라고 생각한다. 이 질문에 대해 대부분의 글들에선 위처럼 단순히 Interrupt에 대해서만 설명하고, 그대로 복사해오는 것 같아서 나름대로 깊게 생각을 해보았다. 

  • 우선 내 생각은 워드라는 프로세스는 멀티 스레드로 구현이 되어있다고 생각이든다.
  • 그렇게 생각한 이유는 커서가 깜박이고, 입출력을 행할 때 다른 행동을 동시에 할 수 있기 때문이다.
  • 따라서 I/O를 처리할 스레드를 만들었을 것이고, 해당 스레드에서 I/O 인터럽트가 걸릴 것이라 생각이 된다.
  • 헌데 I/O 인터럽트가 걸렸다고 해서 해당 프로세스가 통째로 blocked 되지는 않으므로 하나의 커널 스레드만 사용 중인 것은 아닐 것 같다.
  • 즉, 1:1 혹은 m:n으로 스레드 매핑이 이루어져 있을 것 같다.
  • 인터럽트가 발생한 스레드는 이후 인터럽트 처리 과정이 이루어질 것이다.
  • 실행 중이던 스레드가 실행이 중단되고, TCB에 context를 저장한 후, 인터럽트 원인을 판별 -> 인터럽트 벡터 테이블을 참조 -> ISR(인터럽트 서비스 루틴) 처리 -> Interrupt 처리 종료 후 ready 큐에 있는 작업을 실행하면서 상태를 복구할 것 같다.
  • 이후에 화면에 출력해주는 Interrupt가 걸려서, 또다시 같은 과정을 통해 화면에 그려줄 것으로 예상된다.

이후에 더 공부하면서 추가/수정 한 부분

  • 워드 프로세서는 3가지의 스레드를 가진다
    1. interactive 스레드
    2. Reformatting 스레드
    3. Disk-backup 스레드
  • DMA를 이용하여 I/O를 모아서 처리한다.
    • 출력하려면 마지막에 CPU가 인터럽트를 받아서 출력장치에 값을 넘겨줘야 한다.
    • 이때 문제는 한 글자가 4개 블락으로 돼있으면 한 블락당 검사를 해서 4번의 인터럽트가 걸린다고 볼 수 있는데
    • DMA가 이 검사를 대신해줘서 CPU는 한 번의 인터럽트만 받게 된다!
  • 모니터에 화면을 보여주는 것을 계속 I/O Interrupt 가 발생할까?
    • 화면 출력도 프린터 출력하는 거랑 비슷하게 cpu 거쳐가서 커널 스레드가 하드웨어한테 작업을 부여해줄 뿐 실질적인 출력 실행에는 cpu가 쓰이지 않는다.


(질문2) Chrome 은 멀티 프로세스일까? 멀티 스레드 일까?

이에 대한 정말 정확하고 명쾌한 설명이 담긴 아티클을 첨부하겠다

https://d2.naver.com/helloworld/2922312

 

 

 

Reference

- https://d2.naver.com/helloworld/2922312

1. UNIX에서 프로세스의 생성

fork() 시스템 호출은 새로운 프로세스를 만들어내는 기능을 한다.
새로운 프로세스는 원래의 프로세스 주소 공간의 복사본을 가지고 있다.
fork() : 현재 돌아가고 있던 프로세스를 복사해서 다른 프로세스를 만든다.
exec() : 프로세스로 하여금 다른 바이너리를 가지고 새로 시작하도록 한다. 자식 프로세스는 exec을 통해 내용을 모두 바꾼다.

 

2. 프로세스 삭제

프로세스는 마지막 statement를 실행하고 exit() 시스템 호출을 이용하여 운영체제로 하여금 삭제하도록 한다.
부모는 자식에게서 wait을 통해 상태 값을 받을 수 있다.

3. 좀비 프로세스

1. 좀비 프로세스란?

자식 process가 종료되어 자원 해제를 요청했는데 부모 프로세스가 자식 프로세스의 종료 상태를 받아들이지 못해서 프로세스 테이블에 남아 있는 상황이다. 그래서 죽었지만 살아있는 '좀비'와 같은 상태가 된다. 

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
 
int main() {
     
    pid_t childPid;
     
    childPid = fork();
     
    if(childPid > 0) {  // 부모 프로세스
        printf("부모 PID : %ld, pid : %d\n",(long)getpid(), childPid);
        sleep(30);
        printf("부모 종료\n");
        exit(0);
    }
    else if(childPid == 0){  // 자식 코드
        printf("자식 시작 PID : %ld\n", (long)getpid());
        sleep(1);
        printf("자식 종료\n");
        exit(0);
    }
    else {  // fork 실패
        perror("fork Fail! \n");
        return -1;
    }
     
    return 0;
}

 

2. 좀비 프로세스의 목적

좀비상태의 목적은 나중에 parent process가 가져갈 child에 대한 정보를 유지하는 것이다. 이 정보는 자식의 프로세스 ID와 종료 상태 및 자식의 자원 사용률(CPU 시간, 메모리 등) 등을 포함하고 있다.

 

3. 좀비 프로세스가 생겼을 때 제거되는 과정

만약 프로세스가 종료하고 좀비 상태에 있는 자식을 가지고 있으면, 모든 좀비 자식의 어버이 프로세스 ID는 1(init 프로세스)로 바뀌며, 그 프로세스는 자식을 넘겨받아 청소한다. 즉, 좀비를 제거한다 (init은 그들을 wait 한다).

 

4. 좀비 프로세스가 생기지 않도록 처리

그렇다면 좀비프로세스는 어떻게 처리할까? 좀비 프로세스를 내버려 두어서는 안 된다. 좀비는 커널의 공간을 차지하므로, 궁극에는 프로세스를 더 만들 수 없게 된다. 자식을 fork()할 때마다 자식이 좀비가 되는 것을 방지하기 위해 반드시 자식을 wait 해야 한다. 이렇게 하기 위하여 SIGCHLD 신호를 포착하는 신호 처리기를 설정하여 그 신호 처리기 안에서 wait를 호출한다.

Signal(SIGCHLD, sig_chld);

 

4. 고아 프로세스 (Orphan process)

부모 process가 먼저 종료 → 고아 프로세스의 부모 프로세스 PID=1로 변경 (init 프로세스)

 

 

 

 

Reference

- [프로세스 생성]

- [좀비  프로세스 처리] UNIX Network Programming 3rd edition 책

 

 

1. Process란?

  • 프로세스는 운영체제로부터 자원을 할당받아 실행하는 작업의 단위
  • 실행 중인 프로그램으로 → 메모리에 load 되어 있는 상태
  • 운영체제로부터 주소 공간, 파일, 메모리 등을 할당받는다
  • 스택, 힙, 데이터, 코드로 구성된 프로세스 메모리를 갖는다.
  • 비동기적 행위를 일으키는 주체
  • 프로세스 상태: New, Running, Waiting, Ready, Teminated

 

2. Process와 Program 차이점

  • 프로그램 : 명령어들의 집합 (Set of Instructions)
  • 프로세스 : 실행 중인 프로그램 (Program in excution)
    • 실행한다? 메모리에 로드되어 있는 상태

 

3. PCB (Process Control Block)

  • PID, 상태, PC (Program Counter), CPU register, 우선순위 등
  • Linked List 방식으로 관리함 → 삽입, 삭제 용이

 

4. 프로세스의 상태

 

new : 프로세스 생성중

프로세스를 생성하고 있는 단계로 커널 공간에 PCB가 만들어진 상태

 

ready : 프로세스가 CPU를 기다리는 상태

프로세스가 메모리에 적재된 상태로 실행하는데 필요한 자원을 모두 얻은 상태

아직 CPU를 받지는 않았지만 CPU를 할당받으면 바로 실행 가능한 상태

ready상태를 가지는 여러 개의 프로세스들이 존재할 수 있음

 

running : 프로세스가 CPU를 할당받아 명령어를 수행 중인 상태

일반적으로 CPU가 하나이기 때문에, 여러 프로세스가 동시에 실행돼도 실제로 실행 중인 프로세스는 매 시점 하나뿐임

 

blocked : 프로세스가 CPU를 할당받아도 당장 실행할 수 없는 상태

현재 프로세스가 I/O 작업 등을 을 처리 중 상태를 의미

                  

terminated : 프로세스의 실행 종료

프로세스의 실행이 완료되고 할당된 CPU를 반납, 커널 공간 내의 PCB는 남아 있음

 

suspended : 프로세스의 중지 상태

suspended 상태의 프로세스는 메모리를 강제로 뺏긴 상태로 특정한 이유로 프로세스의 수행이 정지된 상태를 의미하며, 외                  부에서 다시 재개시키지 않는 이상 다시 활성화될 수 없음 중기 스케줄러에 의해 디스크로 스왑 아웃된 프로세스의 상태가 대표적인 suspenden상태라 할 수 있음. suspended ready와 suspended  blocked가 있음

 

1. suspended ready : 준비 상태에 있던 프로세스가 디스크로 스왑 아웃

2. suspended blocked : 봉쇄 상태에 있던 프로세스가 디스크로 스왑 아웃

 

 

※ blocked?

프로세스 A가 CPU를 할당받고(running상태) 명령어를 실행하다 I/O 작업을 해야 하는 경우, 디스크 I/O 작업은 CPU 처리 속도에 비해 오래 걸리는 작업이기 때문에 디스크 I/O 작업 동안은 CPU를 점유하고 있어도 다음 명령어를 수행하지 못합니다. ㅡ> CPU 낭비

 때문에 디스크 I/O 작업을 하는 프로세스는 CPU를 반납하고 장치 큐에 가서 줄을 서게 된다(blocked 상태). 이후 디스크 컨트롤러에 의해 서비스를 받아 일을 수행하면(마그네틱 원판에서 원하는 데이터를 로컬 버퍼로 읽어오고 나면) 디스크 컨트롤러가 CPU에게 일을 끝났음을 알린다(인터럽트). 이후 프로세스 A는 장비 큐에서 빼내어 준비 큐로 넣어주고 프로세스 A가 한 일(로컬 버퍼에 저장)은 메모리에 올라가게 된다.

 

※ blocked와 suspended의 차이

blocked : 잠시 중지되어있다(blocked) 끝나면 다시 ready상태로 돌아옴 

suspended : 잠시 중지되어 있다(suspendedn) 누군가가 재개시켜줘야 다시 ready상태로 돌아옴.

 

 

5. 프로세스의 상태 변화

new  ㅡ>  ready

new 상태에서 OS에 의해 승인을 받아 프로세스가 생성되면 해당 프로세스의 PCB(Process Control Block, 커널 내 자료구조)이 OS 커널의 Ready Queue에 올라옴

 

ready ㅡ> running

Ready Queue에 있는 프로세스들 중에서 스케줄링 알고리즘에 의해 선택받은 프로세스가 CPU를 할당 받음

 

running ㅡ> ready

CPU를 할당받아 일을 하다 특정 이유로 다른 프로세스에게 CPU를 주고(dispatch) 다시 CPU를 기다림

 

1. time out : 프로세스 A가 정해진 시간만큼 CPU를 사용하고 CPU를 반납

2. interrupt : 프로세스 A보다 우선순위가 높은 프로세스 B가 Ready Queue에 존재하는 경우, 프로세스 B에게 CPU를 줌

 

running ㅡ> blocked

현재 CPU를 받아 명령어를 수행 중인 프로세스가 I/O 작업을 해야 하는 경우로 CPU를 반납하고 해당 장치 큐에 들어가게 되며 이 상태를  blocked 상태라 함

 

blocked ㅡ> ready

I/O 작업을 위해 장치 큐에 있던 프로세스가 디스크 컨트롤러에 의해 서비스를 받아 일을 하고 디스크 컨트롤러가 인터럽트를 발생하여 프로세스가 한 일을(로컬 버퍼에 저장된 데이터) 메모리에 올려놓고 프로세스는 다시 Ready Queue에 들어가게 됨 

                                                                            

running ㅡ> terminated

프로세스 실행이 완료되어 자원을 반납한 상태

 

blocked, ready -> suspended blocked, suspended ready

봉쇄, 준비상태에 있던 프로세스들이 어떠한 요인에 의해 suspended 상태

suspended blocked인 프로세스가 봉쇄되었던 조건을 만족하게 되면 suspended ready 상태로 바뀌게 된다. suspended 상태에 있는 프로세스들은 메모리를 조금도 보유하지 않고 디스크로 통째로 swap out 된 상태로 존재하게 된다

ex)) 대표적으로 메모리가 부족하여 봉쇄, 준비상태의 프로세스들이 디스크로 swap 되는 경우

 

 

6. Context-Switching : 프로세스 vs 스레드

  • 프로세스는 운영체제로부터 자원을 할당받아 실행하고, 스레드는 프로세스로부터 자원을 할당받아 실행합니다.
  • 프로세스 : fork()를 통해 생성되는데, 매번 동일한 코드가 복사되어 작동하고, PCB, 주소 복사 등 Context Switching에 Cost가 크다.
  • 스레드 : 레지스터와 스택을 제외하고 자원을 공유하여 사용 → 한 가지 스레드는 I/O를 담당하는 등, 스레드로 각 CPU에 일을 할당해서 수행 가능

 

 

 

 

 

Reference

[프로세스의 상태] https://kosaf04pyh.tistory.com/190

 

 

 

프로세스의 주소 공간

Code, Data, BSS, Heap, Stack

 

코드 (Code / Text)

  • 작성한 코드가 기계어 명령으로 변환되어 저장되는 영역
  • 이 부분은 컴파일 후에 바뀌지 않으므로 같은 프로그램에서 이 코드 부분을 공유하여 메모리 사용량을 줄이기 위해 존재

데이터 (Data)

  • 초기화된 전역 변수, 정적 변수와 배열, 구조체가 존재,
  • 프로그램 실행 시 생성, 종료 시 반환,
  • 함수 내부 정적 변수는 프로그램 실행 시 공간만 할당하고 함수 실행 시 초기화

BSS (Block Stated Symbol)

  • 초기화되지 않은 데이터 저장

힙 (Heap)

  • 동적 할당 (malloc, new)된 데이터가 저장, 런타임에 크기가 결정,
  • 힙 영역에 할당한 다 쓴 메모리를 반환하지 않으면 메모리가 부족해지는 것을 ‘메모리 누수’

스택 (Stack)

  • 임시 메모리 영역으로 지역 변수, 매개 변수, 반환 값 등이 잠시 저장, 함수의 호출이 끝나고 돌아갈 반환 주소, 함수 내의 지역 변수 등이 저장되는 정보를 ‘스택 프레임’이라고 함
  • 런타임에 크기가 결정되지만, 런타임에 스택의 총 사이즈를 변경 못함

추가 정보

  • 코드,데이터,스텍 영역은 컴파일러가 결정, 힙은 개발자가 결정
  • 스택은 상위 메모리부터 할당, 나머지는 하위 메모리부터 할당

오버플로우

  • heap overflow : heap이 주소 값을 채우며 내려오다가 stack 영역을 침범
  • stack overflow : stack이 밑에서부터 주소 값을 채우며 올라오다가 heap 영역을 침범

 

프로세스의 주소 공간

 

 

Reference

[동적 할당- 런타임, 컴파일 할당] 

 

'CS > 운영체제 (OS)' 카테고리의 다른 글

8. IPC (Inter-Process Communication)  (0) 2021.08.11
7. 프로세스 vs 스레드  (0) 2021.08.11
3. 인터럽트 (Interrupt)  (1) 2021.08.08
2. 커널 (Kernel)  (0) 2021.08.06
1. 운영체제 (OS) & 부팅과정  (0) 2021.08.06

개요

그동안 학교에서 배웠던 내용 + 전공책을 뒤져가며 공부했던 내용 + 취준 하면서 복습했던 내용들을 정리하는 목적으로 작성하였습니다.

 

1. 인터럽트(Interrupt) 란?

Interrupt는 프로그램 실행 중에 CPU의 현재 처리 순서를 중단하고, 다른 동작을 수행하도록 요구하는 것이라고 볼 수 있다. 즉, Interrupt가 발생하면 운영체제는 CPU에게 그동안 하고 있는 일들을 멈추고, Interrupt를 해결하도록 한다.

 

Interrupt가 발생하게 되면, ISR (Interrupt Service Routines)이라는 것이 실행되는데, 이를 인터럽트 핸들러(Interrupt Handler)라고도 한다

 

그렇다면 Interrupt는 어떤 때에 발생하는 것일까? Interrupt는 예외상황에 대한 처리가 필요한 상황에 발생한다. 예외상황에 따라 Interrup는 크게 (1) 외부 Interrupt, (2) 내부 Interrupt, (3) SW Interrupt로 나눌 수 있다.

 

 

1. 외부 Interrupt

외부 Interrupt는 CPU 코어 외부 요인으로 발생하는 것을 말하는데, 전기적인 신호로 CPU에게 Interrupt를 거는 경우로 (1) 전원 이상 Interrupt, (2) I/O Interrupt, (3) 타이머 Interrupt 같은 것들이 있다.

  1. 전원 이상 Interrupt의 경우,
    • 갑자기 전원 공급이 중단되는 경우 CPU에 Interrupt를 걸어 작업 중이던 프로세스를 대피시킬 수 있도록 한다.
  2. I/O Interrupt의 경우,
    • CPU가 I/O 장치 (키보드, 마우스, 프린터 등) 에게 일을 맡기거나, I/O 장치가 CPU에게 정보를 전달해 줄 때 호출된다.
  3. 타이머 Interrupt의 경우,
    • 컴퓨터 내부의 타이머가 CPU에 주기적으로 expired 되었다고 알림을 주는데, 이것이 Interrupt이다. 따라서 하나의 프로그램이 CPU 자원을 너무 오랫동안 점유하지 못하도록 한다. 또한 무한루프가 도는 프로그램도 이 덕분에 종료되고 Context Switch가 발생할 수 있다.
    • (참고) 타이머 Interrupt는 100hz로 인터럽트를 건다. 즉, 10ms 마다 interrupt가 걸린다.

 

 

2. 내부 Interrupt

내부 Interrupt는 CPU 코어 내부에서 프로그램이 실행되면서 Interrupt에 걸리는 경우로 프로그램 검사 인터럽트(Program check interrupt)이다. Exception Interrupt, 혹은 Trap이라고 부른다.  

  • Exception Interrupt (Trap
    • Division by zero
    • Overflow/Underflow
    • 기타 프로그램 Exception

Exception이라는 것은, 결국 예외상황에 대한 의미로, 소프트웨어 내부에서 예외상황을 처리하는 것을 두고 소프트웨어 Interrupt를 Exception으로 보는 경우도 있다. 

 

Trap의 의미는, 특별한 조건을 걸어두고 조건에 부합하는 경우 상황에 맞는 Service Routine이나 Handler 가 실행되도록 하는 것을 의미한다. 따라서 이 경우에는 ISR (Interrupt Service Routines) 혹은 인터럽트 핸들러(Interrupt Handler)가 되겠다.

 

Exception과 Trap 은 프로그래밍 전반적으로도 사용되는 용어이니, 결국은 단어를 어떻게 해석하느냐의 차이인 것 같다. 결국 너무 단어에 매몰되지 말고, 개념을 잘 익히는 것이 중요하다.

 

 

3. 소프트웨어 Interrupt

소프트웨어 Interrupt는 프로그램 처리 중 명령의 요청에 의해서 발생하는 경우로 SVC (SuperVisor Call) 이 있다.

  • SVC (SuperVisor Call)

일반적인 응용 프로그램은 User Mode에서 실행이 되는데, 이 경우 직접 접근할 수 있는 자원에 제한이 있다. 예를 들어 어떤 프로그램이 컴퓨터에 대한 통제권을 갖는 코드를 갖고 있다고 할 때, 이런 것이 허락도 없이 수행될 수는 없는 것이다. 즉, 이러한 자원에 접근하는 명령어는 Supervisor 만 실행할 수 있어야 하고, 이것이 즉, Kernel Mode가 되는 것이다. 즉, 응용프로그램은 SuperVisor Call을 통해 허락을 맡은 후 Supervisor Mode (=Kernel Mode)로 변경하고, 해당 명령을 실행 후, 다시 User Mode로 변경하는 과정을 거치게 된다.

 

운영체제가 제공하는 서비스에 대한 프로그래밍 인터페이스가 System Call이고, System Call을 실행시키기 위한 CPU 명령어가 SVC이다.

 

 

 

2. 인터럽트 처리 과정

요청 → 중단 → 보관 → 인터럽트 처리 → 재개

  1. 인터럽트 요청
  2. 프로그램 실행 중단
    • 현재 실행 중이던 Micro Operation까지 수행
  3. 현재 실행 중인 프로그램 상태 보관
    • PCB(Process Control Block), PC(Program Counter) 저장
  4. 인터럽트 원인 판별
    • 인터럽트를 요청한 장치를 식별 → 인터럽트의 원인을 파악 
    • Interrupt Vector 테이블을 참조하여 호출할 ISR (인터럽트 서비스 루틴)  주소 값을 얻음
  5. ISR (인터럽트 서비스 루틴) 처리
    • 실질적인 인터럽트 처리 작업을 한다.
    • 서비스 루틴 수행 중, 우선순위가 더 높은 인터럽트가 발생하면 재귀적으로 1~5 과정 수행한다
    • 인터럽트 서비스 루틴을 실행할 때 인터럽트 플래그(IF)를 0으로 하면 인터럽트 발생을 방지할 수 있다.
  6. 상태 복구
    • 상태 복구 명령어가 실행되면, 저장해둔 PC(Program counter)를 다시 복원하여 이전 실행 위치로 복원한다.
  7. 중단된 프로그램 실행 재개
    • PCB의 값을 이용하여 이전에 수행 중이던 프로그램을 재개한다.

 

 

3. Interrupt 관련 예시

(질문) 구글 검색창을 클릭 후 빈칸에 커서가 깜빡이고 있다. 이때 hello world를 작성하면 컴퓨터 내부에서 어떤 일이 발생하는가?

  • 사용자 입력 → 외부 Interrupt 중 I/O Interrupt 발생 → CPU 인지 → CPU 작업 중이던 상태 저장 → 해당 인터럽트 처리 → 상태 복구 및 중단되었던 작업 재개

 

 

질문

인터럽트와 시스템 콜의 차이에 대해서 설명하세요.

더보기

Interrupt

  • Interrupt는 프로그램 실행 중에 CPU의 현재 처리 순서를 중단하고, 다른 동작을 수행하도록 요구하는 것이라고 볼 수 있다.
  • 즉, Interrupt가 발생하면 운영체제는 CPU에게 그동안 하고 있는 일들을 멈추고, Interrupt를 해결하도록 한다.

System Call

  • 운영체제가 제공하는 서비스에 대한 프로그래밍 인터페이스가 System Call이고, System Call을 실행시키기 위한 CPU 명령어가 SVC이다.

 

 

Reference.

[인터럽트] https://jhnyang.tistory.com/167

[인터럽트] https://hibee.tistory.com/264

[SVC vs System Call] https://www.techopedia.com/definition/25808/supervisor-call

'CS > 운영체제 (OS)' 카테고리의 다른 글

8. IPC (Inter-Process Communication)  (0) 2021.08.11
7. 프로세스 vs 스레드  (0) 2021.08.11
4. 프로세스의 주소 공간  (1) 2021.08.08
2. 커널 (Kernel)  (0) 2021.08.06
1. 운영체제 (OS) & 부팅과정  (0) 2021.08.06

1. 커널 (Kernel) 이란?

커널은 운영체제(OS)의 주요 구성 요소이며 컴퓨터 하드웨어와 프로세스를 잇는 핵심 인터페이스이다.

커널이라는 이름은 단단한 껍질 안의 씨앗처럼 OS 내에 위치하고 전화기, 노트북, 서버 또는 컴퓨터 유형에 관계없이 하드웨어의 모든 주요 기능을 제어하기 때문에 붙은 이름이다.

 

 

2. 커널의 기능

1) 메모리 관리: 메모리가 어디에서 무엇을 저장하는 데 얼마나 사용되는지를 추적합니다.

2) 프로세스 관리: 어느 프로세스가 중앙 처리 장치(CPU)를 언제 얼마나 오랫동안 사용할지를 결정합니다.

3) 장치 드라이버: 하드웨어와 프로세스 사이에서 중재자/인터프리터의 역할을 수행합니다.

4) 시스템 호출 및 보안: 프로세스의 서비스 요청을 수신합니다.

 

 

3. 이중 실행 모드 (Kernel mode vs User mode)

Kernel mode와 User mode에 대해 살펴보기 전에, 이를 나눈 근본적인 이유가 상당히 중요하다.

응용 프로그램이 시스템 자원에 직접 접근하게 되면 심각한 오류들을 유발할 수 있기 때문에, 각 응용 프로그램이 시스템 자원에 직접 접근하지 못하도록 하기 위해서 나누어 놓았다. 따라서, 자원에 대한 접근 권한은 커널에게만 부여하여, 자원에 대한 접근이 필요한 시점에는 System call을 통해서 간접적으로 실행하도록 하였다. 결국 자원에 대한 접근은 커널을 통해서만 접근할 수 있는 것이다.

 

1. 커널 모드 (Kernel mode / SuperVisor mode)

커널 모드에서 운영체제는 모든 하드웨어에 대한 완전한 접근이 가능하며, 기계가 실행할 수 있는 어떤 명령도 실행할 수 있다. 즉, Kernel mode는 운영체제가 CPU의 제어권을 가지고 명령을 수행하는 모드로 일반 명령과 특권 명령 모두 수행할 수 있다. 또한 모든 주소 공간에 접근이 가능하다.

 

2. 유저 모드 (User mode)

유저 모드 기계 명령 중 일부만을 실행할 수 있는 모드로, 특별히 기계의 제어에 영향을 미치거나 I/O를 하는 명령들은 사용자 모드에서 실행할 수 없다. 즉, User mode는 일반 사용자 프로그램이 CPU 제어권을 가지고 명령을 수행하는 모드이기 때문에 일반 명령만을 수행할 수 있다. 또한 사용자 주소 공간만 접근이 가능하다.

 

운영체제 구조

 

4. 일반/특권 명령

CPU가 수행하는 명령에는 2가지 명령이 있는데, 명령을 다음과 같이 구분하여 부적절한 사용을 막는다.

 

일반 명령은 메모리에서 자료를 읽어와 CPU에서 계산하고 결과를 메모리에 쓰는 등의 명령이고, 모든 프로그램이 수행할 수 있는 명령이다. 따라서 사용자 응용 프로그램은 특권 명령을 사용하지 못합니다.

 

특권 명령은 프로세스 제어, 파일 조작, 장치(I/O, 타이머 등) 조작, 정보 유지 보수, 통신, 보호 등의 명령으로, 항상 운영체제에서만 수행할 수 있으며, 특권 명령을 사용하고 싶을 때 사용하는 것이 바로 '시스템 콜'이며 OS에게 특권 명령을 대신 실행해달라고 요청하는 것입니다.

 

5. 논리 주소 공간

1. 사용자 주소 공간 (User space)

  • 각 응용 프로그램이 나누어 적재되고 사용되는 공간

2. 커널 주소 공간 (Kernel space)

  • 커널에 의해 배타적으로 사용 - 커널 코드, 커널 데이터, 디바이스 드라이버 등

 

커널

 

6. 커널과 관련된 Issue

1. 커널은 스스로 실행되는 프로세스인가?

  • X, 시스템 호출을 통해 호출되는 단순 함수/데이터의 집합

2. 커널은 실행 중이다?

  • X, 시스템 호출/인터럽트를 통해 커널 코드/ISR이 실행되고 있을 뿐이다. (능동적인 주체 x, 수동적인 대상 o)

3. 커널은 스택이나 힙을 갖는가?

  • X, 각 프로세스/스레드가 스택/힙 소유
    • app이 커널 코드 실행 시, 커널 공간에 커널 코드 실행을 위한 스택 생성, 복귀 시 해제
  • 커널은 하나의 프로세스가 아니므로 그 자신만의 스택/힙을 갖지 않는다. 사용자 프로그램이 시스템 호출을 통해 간접적으로 커널 함수를 호출하게 되면, 현재 커널 코드의 실행을 위해 커널 영역에 stack이 임시로 생성이 될 수는 있다. 하지만 이는 커널이 관리하는 것이 아니라, 사용자 프로그램의 요청을 처리하기 위해 임시로 만들어진 stack/heap 에 불과하다. 따라서 시스템 호출을 마무리하고 복귀하면 없어진다.

 

 

Reference

[커널] https://www.redhat.com/ko/topics/linux/what-is-the-linux-kernel

[Modern Operating Systems 3rd]

 

'CS > 운영체제 (OS)' 카테고리의 다른 글

8. IPC (Inter-Process Communication)  (0) 2021.08.11
7. 프로세스 vs 스레드  (0) 2021.08.11
4. 프로세스의 주소 공간  (1) 2021.08.08
3. 인터럽트 (Interrupt)  (1) 2021.08.08
1. 운영체제 (OS) & 부팅과정  (0) 2021.08.06

+ Recent posts