호댕의 iOS 개발

[운영체제] 운영체제(OS)란 무엇이고 프로세스와 스레드는 뭘까? 본문

Software Engineering

[운영체제] 운영체제(OS)란 무엇이고 프로세스와 스레드는 뭘까?

호르댕댕댕 2022. 7. 18. 21:54

일단 컴퓨터 시스템의 경우 네 가지 구성요소를 가지고 있다.

  • 하드웨어 : 중앙처리장치(CPU), 메모리(RAM), 입출력 장치(I/O Device)로 구성이 되어 있음
  • 운영체제 : 다양한 사용자를 위해 다양한 응용 프로그램 간 하드웨어 사용을 제어하고 조정한다. 즉, 다른 프로그램이 원활하게 작업을 할 수 있는 환경을 제공해주는 역할을 한다. (제어 프로그램의 역할 수행)
  • 응용 프로그램 : 컴파일러, 웹 브라우저 등 사용자의 계산 문제를 해결하기 위해 자원이 어떻게 사용될 지를 정의함
  • 사용자

 

운영체제란

운영체제는 컴퓨터에서 항상 실행되는 프로그램으로 일반적으로 커널이라 부른다. 

운영체제가 하드웨어를 컨트롤하게 되며 컴퓨터의 전원을 연결했을 때 컴퓨터가 동작할 수 있도록 운영체제를 로딩해야 한다. 컴퓨터의 CPU는 메모리에서만 명령을 적재할 수 있기 때문에 실행하려면 먼저 프로그램을 메모리에 올려야 하고 이를 부트스트랩 프로그램이라 부른다. (컴퓨터 전원을 켤 때 가장 먼저 메모리에 올라가는 프로그램이다)

 

그렇다면 "코어"는 뭘까?

코어는 명령을 실행하고 로컬에 데이터를 저장하기 위한 레지스터를 포함하는 구성요소로 CPU 계산의 기본 단위이다.

 

Multi Programming과 Multi Tasking

MultiProgramming은 CPU가 항상 한 개의 프로그램을 실행하도록 되어 있으며, CPU의 이용률을 올려 사용자의 만족도를 올릴 수 있도록 한다. 

MultiTasking의 경우 MultiProgramming을 확장한 개념이다. 항상 하나의 프로그램을 실행 중이긴 하나, CPU가 여러 프로세스를 빠르게 자주 전환하면서 동시에 업무를 처리하고 있는 것처럼 보이게 하는 것이다. 

 

이렇게 업무를 어떻게 전환하면서 처리할지 결정내리는 것이 바로 CPU 스케쥴링이다. 

 

운영체제의 프로그램 실행 환경

운영체제는 프로그램과 프로그램의 사용자에게 특정 서비스를 제공하며 작업을 더 쉽게 수행할 수 있도록 한다. 이를 위해 거의 모든 운영체제는 사용자 인터페이스(UI)를 제공하게 된다. 

  • 그래픽 사용자 인터페이스(GUI) : 화면을 선택하는 포인팅 장치인 마우스와 텍스트를 입력할 키보드 등을 통해 화면을 클릭하여 프로그램을 호출하거나, 파일 / 디렉토리를 선택할 수 있다. 
  • 명령어 라인 인터페이스(CLI) : 명령어를 입력하여 실행하게 된다 (ex: shells)
  • 터치스크린 인터페이스 : 현재 많이 사용하는 Android나 iOS가 대표적인 예시이다. 화면을 직접 터치하여 선택한다. 

 

프로세스(Process)

실행 중인 프로그램을 말하며, 현대의 컴퓨팅 시스템에서의 작업 단위이다. 이는 리소스 즉, CPU Times / 메모리 / 파일 / I/O Devices를 관리할 수 있어야 한다. 

CPU가 실행할 프로그램을 메모리에 로드해놓은 상태를 의미하는 것이다. 

프로세스의 메모리 배치의 경우 텍스트(코드) / 데이터 / 힙 / 스택으로 구성되어 있다. 

  • 텍스트 : 실행 코드가 올라간다. 
  • 데이터 : 전역 변수나 클래스 등이 올라간다. 
  •  : 런타임에 동적으로 할당되는 영역으로 대표적으로 클래스의 인스턴스가 올라간다. 
  • 스택 : 함수를 호출할 때 임시로 올라갔다가 종료되는 경우 메모리에 내려오게 된다. 대표적으로 구조체의 인스턴스나 지역변수, 함수의 매개변수 등이 올라가게 된다. 

프로세스의 상태

  • New : 프로세스가 생성 중 
  • Ready : 프로세스가 처리기에 할당되기를 기다림
  • Waiting : 프로세스가 어떤 이벤트(I/O 완료나 특정 신호의 수신)이 일어나기를 기다림
  • Running : 명령어들이 실행 중인 상황 (CPU를 점유하고 메모리에서 fetch해온 상태)
  • Terminated : 프로세스의 실행이 종료

 

프로세스 제어 블록 (Process Control Block, PCB)

특정 프로세스와 연관된 여러 정보를 수록하고 있는 운영체제의 자료구조이다. 프로세스 생성과 동시에 고유한 PCB를 생성하게 된다. 

<PCB에 저장되는 정보>

  • 프로세스 상태
  • 프로세스 식별자(Process ID, PID)
  • 프로그램 카운터 : 프로세스가 다음에 실행할 명령어의 주소 (Context Switch 관련)
  • CPU레지스터 : 나중에 프로세스가 다시 스케줄될 때 올바르게 실행하도록 하기 위해 인터럽트 발생 시 저장되야 함(Context Switch 관련)
  • CPU 스케줄링 정보 : 프로세스 우선순위, 스케줄 큐에 대한 포인터, 다른 스케줄 매개변수를 포함
  • 메모리 관리 정보 : 운영체제가 사용하는 메모리 시스템에 따라 페이지 테이블 또는 세그먼트 테이블 등과 같은 정보 포함
  • 입출력 상태 정보 : 프로세스에 할당된 입출력 장치들과 열린 파일 목록
  • Accounting 정보 : CPU 사용 시간과 경과된 실시간, 시간 제한, 계정 번호, 프로세스 번호 등 

Context Switch (여기서 Context는 프로세스가 사용 중인 상태를 말함)가 발생하게 되면 진행하고 있던 작업을 저장하고 새로운 프로세스의 보관된 상태를 복구하는 작업이 필요하다. 이 때 이런 진행 상황들을 전부 PCB에 저장하게 된다. 

 

프로세스 간 통신(Interprocess Communication, IPC)

프로세스가 시스템에서 실행 중인 다른 프로세스들과 데이터를 공유하지 않는다면 CPU 스케줄링만 잘해주면 된다. 다만 다른 프로세스들과 데이터를 공유하게 된다면 이는 협력적인 프로세스로 다른 프로세스들과 성공적으로 자료를 공유하기 위해 IPC 매커니즘이 필요하게 된다. 

 

이 때 사용할 수 있는 방법은 다음과 같다. 

  • 공유 메모리 (Shared Memory)
  • 메시지 전달 (Message Passing)

<공유 메모리>

정보를 생산하는 프로세스를 생산자 프로세스, 정보를 소비하는 프로세스를 소비자 프로세스라고 한다. 여기서 생산자-소비자 문제가 발생하게 된다. 그래서 사용할 수 있는 것이 바로 공유 메모리이다. 

생산자가 정보를 채워넣으면, 소비자가 이를 소모할 수 있도록 버퍼를 사용 가능하도록 하는 것이다. 일반적으로 우리가 사용하는 버퍼는 일정 크기가 고정되어 있는 유한 버퍼이다. 

 

다만 이 방법의 경우 프로그래머가 직접 버퍼를 설정해줘야 한다는 불편함이 존재한다. 

<메시지 전달>

이는 OS가 알아서 처리를 해주는 방식이다. 

  • 직접 통신 : 통신을 원하는 각 프로세스는 통신의 수신자 또는 송신자의 이름과 메시지를 작성해줘야 한다. 
    - send(P, message) : 프로세스 P에 메시지를 전송한다. 
    - recieve(Q, message) : 프로세스 Q로부터 메시지를 수신한다. 
    • 프로세스는 통신하기 위해 상대방의 Identity를 알고 있어야 한다. 
    • 연결은 정확히 2개의 프로세스 간에만 가능하다. 
    • 각 쌍의 프로세스 간에 정확히 1개의 연결만 있어야 한다. 
  • 간접 통신: 메일박스 또는 포트로 송신이 되고 이를 통해 수신한다.
    - send(A, message) : 메일박스 A에 메시지를 전송한다. 
    - recieve(A, message) : 메일박스 A로부터 메시지를 수신한다. 
    • 한 쌍의 프로세스 간 연결은 프로세스가 공유 포트를 가질 때에만 생긴다. 
    • 연결은 2개 이상의 프로세스와 연관될 수 있다. 
    • 프로세스 간에는 다수의 서로 다른 연결이 존재할 수 있고, 각 연결은 하나의 포트에 대응된다. 

 

 

스레드 

현대 대부분의 운영체제는 하나의 프로세스에 다중 스레드를 포함하고 있다. 스레드는 CPU 이용의 기본 단위로 스레드 ID, 프로그램 카운터(PC: 다음에 실행할 명령어의 주소), 레지스터 집합, 스택으로 구성되어 있다. 같은 프로세스에 속한 다른 스레드들은 코드, 데이터, 힙, 파일이나 신호를 공유하게 된다. 

 

멀티스레딩을 사용하는 경우 장점

  • 응답성 : 시간이 오래 걸리는 연산(이미지 로드 등)이 별도의 비동기 스레드에서 실행된다면 연산을 처리하면서 여전히 사용자에게 응답이 가능하게 된다. 
  • 자원 공유 : 프로세스의 경우 공유 메모리를 사용하거나 메시지 전달을 통해서만 자원을 공유할 수 있지만, 스레드의 경우 프로세스의 자원 즉, 코드 / 데이터 / 파일 / 신호 등을 자동으로 공유하고 있다. 
  • 경제성 : 프로세스 생성을 하는 경우 메모리와 자원 관점에서 비용이 큰 것에 반해 스레드의 경우 프로세스의 자원을 공유하면서, 스레드를 생성하고 Context Switch를 하는 것이 훨씬 경제적이다. 
  • 규모 적응성 : 각각의 스레드가 병렬로 동작하면서 이점을 가지게 된다. 

 

이런 멀티 스레딩을 잘 활용하기 위해선 다음과 같은 것들을 준수해야 한다. 

  • 태스크 인식: 독립적으로 병행이 가능한 태스크인지 확인해야 한다. 예를 들어 정렬을 하는 경우 쪼개서 정렬을 한다고 하더라도 일정 부분의 정렬이 끝나야 다음 정렬을 할 수 있기 때문에 완전히 병렬로 작동하지 않는다. 
  • 균형: 전체 작업이 균등한 기여도를 가지도록 태스크를 나눈다. 
  • 데이터 분리: 독립된 태스크로 나누는 것처럼, 태스크가 접근하고 조작하는 데이터 또한 개별 코어에서 사용할 수 있도록 해야 한다. 
  • 데이터 종석성: 데이터가 둘 이상의 태스크 사이에 종속성이 있는지 검토해야 한다. 
  • 시험 및 디버깅: 프로그램이 다중 코어에서 병렬로 실행될 때 다양한 실행 경로가 생기면서 단일 스레드를 시험하고 디버깅하는 것보다 훨씬 어렵게 된다. 

 

멀티 스레딩의 문제점 

  • 스레드는 데이터를 공유하기 때문에 보안 문제가 발생할 수 있다. 
  • 스레드의 한 부분에서 문제가 생기거나 버그가 발생하면 전체 프로세스가 멈춰버린다. 
  • 멀티스레딩을 하게 되면 동시에 공유 자원에 접근하면서 Race Condition이 발생할 수 있다. 

 

참고자료

- 운영체제, http://www.yes24.com/Product/Goods/89496122

- https://bit.ly/3IJ2Zbb

 

Comments