워밍업 클럽 CS 1주차 발자국 : 운영체제
운영체제 들어가기
운영체제 개요
운영체제(OS, Operating System)는 컴퓨터 하드웨어와 사용자 간의 중개자 역할을 하는 소프트웨어입니다.
컴퓨터 자원(CPU, 메모리, 디스크, 네트워크 등)을 효율적으로 관리하고, 사용자와 응용 프로그램이 하드웨어를 쉽게 사용할 수 있도록 도와주는 역할을 합니다. 운영체제는 여러 작업을 동시에 처리할 수 있도록 프로세스를 관리하고, 파일 시스템, 네트워크 통신, 보안 등을 담당하며, 하드웨어 장치와 소프트웨어 간의 인터페이스 역할도 합니다.
운영체제가 하는 주요 기능:
1. 프로세스 관리: 실행 중인 프로그램(프로세스)을 관리하고, 여러 프로세스가 동시에 실행될 수 있도록 스케줄링과 자원 배분을 조절.
2. 메모리 관리: 실행 중인 프로그램들이 메모리를 효율적으로 사용하도록 조정하고, 메모리 간 충돌을 방지.
3. 하드웨어 관리: CPU, 메모리, 디스크, 입출력 장치 등의 하드웨어 자원을 관리하고, 응용 프로그램이 이 자원에 접근할 수 있도록 인터페이스를 제공.
4. 파일 시스템 관리: 데이터를 파일 단위로 저장하고, 사용자가 이를 읽고 쓸 수 있도록 파일 관리 시스템을 제공.
5. 보안 및 접근 제어: 시스템 자원에 대한 접근을 제어하고, 권한을 부여해 사용자의 보안을 유지.
운영체제는 다양한 하드웨어를 제어하며 컴퓨터 시스템의 효율성과 안정성을 보장하는 중요한 소프트웨어입니다. 대표적인 운영체제에는 윈도우(Windows), 리눅스(Linux), 맥OS(macOS) 등이 있습니다.
운영체제 역사
운영체제는 애니악 같은 초기 컴퓨터부터 발전해 왔습니다. 초기에는 입출력 작업과 같은 기본 기능만 수행했지만, 시분할 시스템의 도입으로 멀티프로그래밍과 다중 사용자 환경이 가능해졌고, 이 시기에 유닉스가 탄생했습니다. 이후, 개인용 컴퓨터가 상용화되면서 현대의 운영체제가 발전했습니다.
운영체제는 CPU 사용률을 높이고 비용을 절감하려는 노력에서 시작되었습니다.
운영체제의 구조
운영체제의 구조는 커널, 사용자 인터페이스, 하드웨어와의 상호작용으로 나눌 수 있습니다.
커널(Kernel): 운영체제의 핵심으로, 프로세스, 메모리, 저장장치를 관리합니다. 커널은 사용자가 직접 접근할 수 없으며, 커널이 사용자로부터 자신을 보호하기 위한 인터페이스인 시스템 콜을 통해 응용 프로그램과 소통합니다.
사용자 인터페이스: 사용자와 커널 간의 상호작용을 위해 GUI(그래픽 사용자 인터페이스)나 CLI(명령 줄 인터페이스)를 제공합니다. 사용자는 시스템 콜을 통해 커널의 기능을 요청합니다.
하드웨어와의 상호작용: 커널은 디바이스 드라이버를 사용하여 하드웨어를 제어합니다. 드라이버는 하드웨어와 커널 간의 통신을 담당하며, 기본적인 드라이버는 커널에 포함되지만 복잡한 장치는 제조사에서 제공하는 드라이버를 설치해야 합니다.
컴퓨터 하드웨어와 구조
오늘날의 대부분의 컴퓨터는 프로그램 내장 방식의 폰 노이만 구조를 따릅니다. 과거의 애니악 같은 컴퓨터는 하드웨어로 프로그램을 구성해야 했으며, 프로그램 변경 시마다 스위치와 배선을 재조정하는 불편함이 있었습니다.
폰 노이만 구조의 주요 요소:
CPU: 중앙 처리 장치로, 모든 연산과 제어를 담당합니다.
BUS: 데이터를 전달하는 통로 역할을 합니다.
메모리 (RAM): 프로그램을 실행하기 위해 메모리에 올리는 방식입니다. 프로그램이 메모리에 내장되어 실행되므로, 소프트웨어만 교체하면 됩니다.
메인보드:
하드웨어 연결 장치: 다양한 하드웨어를 연결하여 통합하는 역할을 합니다.
데이터 전송: 장치 간의 데이터 전송은 메인보드의 버스가 담당합니다.
CPU는 크게 산술논리 연산장치(ALU), 제어장치(Control Unit), 레지스터(Register)로 나눌 수 있습니다:
산술논리 연산장치 (ALU):
CPU에서 실제 데이터 연산을 수행하는 장치로, 산술 연산(덧셈, 뺄셈 등)과 논리 연산(AND, OR, NOT 등)을 처리합니다.
제어장치 (Control Unit):
CPU 내 모든 장치의 동작을 지시하고 제어하는 역할을 하며, 프로그램 명령어를 해석하여 ALU와 레지스터 등 다른 장치의 동작을 조정합니다.
레지스터 (Register):
CPU 내부에서 계산을 위해 임시로 데이터를 보관하는 장치로, 변수를 저장하는 역할을 합니다. 레지스터는 빠른 데이터 접근 속도를 제공합니다.
메모리는 크게 RAM과 ROM으로 구분되며, 각각의 특징은 다음과 같습니다:
RAM (Random Access Memory):
저장된 위치와 관계없이 읽는 속도가 일정합니다.
휘발성 메모리로, 전원이 꺼지면 데이터가 사라집니다.
주로 메인 메모리로 사용되어, 현재 실행 중인 프로그램과 데이터를 임시로 저장합니다.
ROM (Read Only Memory):
비휘발성 메모리로, 전원이 꺼져도 데이터가 유지됩니다.
데이터가 한 번 쓰이면 수정할 수 없습니다.
주로 컴퓨터 부팅과 관련된 BIOS를 저장하는 데 사용됩니다.
컴퓨터 부팅 과정
전원 공급: 컴퓨터 전원이 켜지면 하드웨어에 전력이 공급되고, 프로세서가 초기화되면서 부팅이 시작됩니다.
BIOS 실행: 컴퓨터의 메인보드에 내장된 ROM(Read-Only Memory)에 저장된 BIOS(Basic Input/Output System)가 실행됩니다. BIOS는 컴퓨터의 기본적인 입출력 기능을 담당하며, 부팅 초기 단계에서 중요한 역할을 합니다.
POST(전원 켠 후 자가 테스트): BIOS는 POST(Power-On Self Test)를 수행하여 CPU, 메모리, 키보드, 마우스, 그래픽 카드, 하드디스크 등 주요 하드웨어 장치가 정상적으로 작동하는지 확인합니다. 문제가 있으면 오류음을 내거나 화면에 오류 메시지를 표시하고, 부팅이 중단됩니다.
부트로더 로드: 하드웨어 점검이 완료되면, BIOS는 저장 장치(주로 하드디스크 또는 SSD)에서 MBR(Master Boot Record)을 찾아 실행합니다. MBR에는 컴퓨터의 첫 번째 부팅 섹터와 부트로더가 저장되어 있습니다.
부트로더 실행: MBR에서 불러온 부트로더는 설치된 운영체제들을 확인하고, 사용자가 부팅할 운영체제를 선택할 수 있도록 합니다. 예를 들어, 컴퓨터에 윈도우와 리눅스가 함께 설치되어 있으면 운영체제 선택 화면이 표시됩니다.
운영체제 로드: 사용자가 운영체제를 선택하거나 기본 운영체제가 하나만 있으면, 선택된 운영체제가 하드디스크에서 메모리로 로드됩니다. 이때 운영체제의 커널이 메모리에 올라가며, 운영체제가 컴퓨터를 제어하기 시작합니다.
바탕화면 표시: 운영체제가 성공적으로 로드되면, 모니터에 바탕화면이 표시되고, 사용자 인터페이스(UI)가 준비됩니다. 이 시점부터는 사용자가 응용 프로그램을 실행하고, 운영체제가 이를 관리하게 됩니다.
인터럽트
인터럽트는 CPU가 입출력 장치와 상호작용할 때 발생하는 중요한 개념입니다.
1. 입출력 작업 시작: CPU가 입출력 작업이 들어오면 입출력 관리자에게 명령을 내립니다.
2. 폴링 방식
CPU는 입출력 명령의 완료 여부를 주기적으로 체크해야 합니다. 이 방식을 폴링(Polling)이라고 합니다.
단점: CPU가 자주 확인해야 하므로 성능이 저하됩니다.
3. 인터럽트의 도입
인터럽트는 폴링의 단점을 해결하는 방식입니다.
CPU는 입출력 명령을 내린 후 다른 작업을 계속 수행합니다.
입출력 관리자가 작업이 완료되면 CPU에 신호를 보내고, CPU는 이 신호를 수신하여 인터럽트 서비스 루틴(ISR)을 실행하여 작업을 완료합니다.
ISR (인터럽트 서비스 루틴):
특정 인터럽트가 발생했을 때 그 인터럽트를 처리하는 함수입니다.
인터럽트의 장점:
인터럽트는 비동기적으로 동작하여 CPU의 성능을 높이는 데 도움을 줍니다.
인터럽트의 종류 :
하드웨어 인터럽트: 입출력 장치에서 발생합니다.
소프트웨어 인터럽트: 사용자 프로그램에서 발생하며, 예를 들어 0으로 나누기 또는 유효하지 않은 명령어에 접근할 때 발생합니다.
프로세스와 스레드
프로그램과 프로세스
프로그램:
하드디스크와 같은 저장장치에 저장된 명령문의 집합체로, 애플리케이션 또는 앱이라고도 함.
컴퓨터 관점에서는 수동적인 존재로, 저장장치에만 존재함.
프로세스:
실행 중인 프로그램을 의미하며, 저장장치에 있는 프로그램이 메모리에 올라갔을 때 형성됨.
능동적인 존재로, 메모리와 CPU를 사용하며 입력과 출력을 처리함.
운영체제의 CPU 스케줄링 알고리즘에 따라 CPU 사용.
프로세스의 구조
코드 영역 : 실행 중인 프로세스의 코드가 저장됨.
데이터 영역: 전역 변수 및 정적 변수가 저장됨.
스택 영역:
지역 변수와 함수 호출에 필요한 정보가 저장됨.
함수 호출 시 매개변수와 복귀 주소를 저장.
힙 영역:
개발자가 런타임 중 동적으로 메모리를 할당할 수 있는 공간.
C 언어에서
malloc
,free
함수를 사용하여 자원 할당 및 해제를 수행.
프로세스 생성 과정 (C 언어의 경우)
전처리: 전처리기를 통해 매크로를 치환하고 필요한 파일을 포함함. 이때 파일의 확장자는
.i
가 됨.컴파일:
컴파일러가 C 언어를 저수준 어셈블리어로 변환함. 파일 확장자는
.s
가 됨.어셈블리:
어셈블러가 어셈블리어를 기계어로 변환함. 결과 파일의 확장자는
.o
가 됨.링킹:
링커가 여러 라이브러리 및 다른 소스코드를 연결하여 최종 실행 파일을 생성함. 확장자는
.exe
가 됨.프로세스 생성:
생성된 실행 파일을 더블 클릭하면 하드디스크에 있는 파일이 메모리에 올라가 프로세스가 형성되며 운영체제에 의해 관리됨.
CPU 관점에서의 프로세스 실행
CPU는 0과 1로 이루어진 기계어만을 실행함.
예를 들어, CPU가 숫자 5와 7을 메모리에 저장하고, 이를 레지스터로 가져옴.
제어장치가 레지스터의 값들을 가지고 더하라는 명령을 내리면, 산술 논리 연산 장치가 두 숫자를 더하고 결과를 레지스터에 저장.
제어장치가 레지스터에서 결과값을 가져와 메모리에 저장함.
멀티프로그래밍과 멀티프로세싱
메모리 관점 :
유니프로그래밍: 메모리에 오직 하나의 프로세스만 올라와 있는 상태입니다.
멀티프로그래밍:
메모리에 여러 개의 프로세스가 동시에 올라와 있는 상태입니다.
CPU 관점 :
멀티프로세싱:
CPU가 여러 개의 프로세스를 동시에 처리하는 방식입니다.
오늘날의 운영체제는 멀티프로그래밍과 멀티프로세싱 두 가지 방식을 공존하여 사용합니다.
멀티프로그래밍:
메모리에 여러 개의 프로세스가 올라와 있으며, 이들 프로세스는 동시에 존재합니다.
시분할 처리:
CPU는 각 프로세스를 짧은 시간 동안 교대로 실행하여 멀티프로세싱을 구현합니다.
과거에는 메모리의 크기가 작아 멀티프로그래밍이 불가능하여 유니프로그래밍과 멀티프로세싱을 사용했습니다.
스와핑 : 메모리에 있는 데이터를 다른 저장장치로 보내고, 다른 저장장치에서 있는 데이터를 메모리에 올리는 과정을 말합니다. 이로 인해 메모리의 활용성을 극대화할 수 있습니다.
PCB : Process Control Block
운영체제는 여러 개의 프로세스를 효율적으로 관리하고 공평하게 실행해야 합니다. 프로세스가 생성되면, 운영체제는 해당 프로세스의 정보를 포함하는 PCB(프로세스 제어 블록)를 생성하고 저장합니다. 이 PCB들은 연결 리스트라는 자료구조로 저장되어 운영체제에서 관리됩니다. 프로세스가 종료되면, 연결 리스트에서 해당 프로세스의 PCB가 제거됩니다.
포인터:
부모 및 자식 프로세스에 대한 포인터와 할당된 자원에 대한 포인터를 포함합니다.
프로세스 상태 전환 시 저장하는 포인터를 갖고 있어 효율적인 접근을 지원합니다.
프로세스 상태:
현재 프로세스의 5가지 상태를 나타냅니다:
생성, 준비,
실행,
대기,
완료
프로세스 ID (PID):
프로세스를 식별하기 위한 고유 숫자를 저장합니다.
프로그램 카운터:
다음에 실행될 명령어의 주소를 포함합니다. 운영체제가 시분할 처리로 여러 프로세스를 번갈아 실행할 때, 어떤 프로세스가 CPU를 빼앗기고 다시 실행될 때 원래의 명령어가 실행될 수 있도록 프로그램 카운터는 필수적입니다.
레지스터 정보:
프로세스 실행 시 사용했던 레지스터 값들이 저장됩니다. 이는 CPU를 빼앗긴 후 다시 시작할 때 이전에 사용하던 값을 복구하기 위한 용도로 사용됩니다.
메모리 관련 정보:
프로세스가 메모리에 있는 위치 정보, 메모리 침범을 방지하기 위한 경계 레지스터 값 등이 저장됩니다.
CPU 스케줄링 정보:
CPU 스케줄링에 필요한 우선순위, 최종 실행 시간, CPU 점유 시간 등이 저장됩니다.
기타 정보:
PCB에는 프로세스의 상태 관리와 관련된 기타 정보도 포함될 수 있습니다.
프로세스 상태
프로세스는 시분할 처리를 위한 다음과 같은 5가지 상태를 갖습니다:
생성 (New):
PCB(프로세스 제어 블록)가 생성되고, 메모리에 프로그램을 적재하기 위한 요청이 이루어지는 상태입니다.
준비 (Ready):
CPU 사용을 기다리는 상태입니다.
준비 상태에 있는 프로세스는 배분된 CPU 스케줄러에 의해 CPU가 할당됩니다.
대부분의 프로세스는 이 준비 상태에 있습니다.
대기 (Waiting):
프로세스가 입출력 요청을 할 때, 해당 요청이 완료될 때까지 기다리는 상태입니다.
CPU는 매우 빠른 반면, 입출력 작업은 상대적으로 느리기 때문에, 특정 프로세스가 입출력 요청을 하면 CPU가 그 프로세스를 기다리게 하는 것은 비효율적입니다.
따라서, 입출력 요청을 한 프로세스는 대기 상태로 전환되고, 다른 프로세스에게 CPU를 할당합니다.
입출력 작업이 완료되면 대기 상태에 있던 프로세스에게 CPU 할당 기회를 줍니다.
실행 (Running):
준비 상태에 있는 프로세스가 CPU 스케줄러에 의해 CPU를 할당받아 실행되는 상태입니다.
CPU가 하나인 경우 실행 상태의 프로세스는 최대 1개만 존재합니다.
실행 상태에 있는 프로세스도 CPU를 무한정 사용할 수 없으며, 부여된 시간만큼 사용합니다.
CPU 스케줄러는 부여된 시간을 초과하면 할당된 CPU를 강제로 뺏고 프로세스는 다시 준비 상태로 전환됩니다.
완료 (Terminated):
프로세스가 종료된 상태입니다.
프로세스가 사용했던 데이터는 메모리에서 제거되고, 생성된 PCB도 제거됩니다.
프로세스 A, B, C가 동시에 실행될 때의 동작 과정:
프로세스 로드:
사용자의 입력에 의해 운영체제는 A, B, C 프로그램을 메모리에 로드합니다.
이 과정에서 각 프로그램에 대한 프로세스 제어 블록(PCB)도 생성됩니다.
CPU 할당:
운영체제는 스케줄러에 의해 A 프로세스에 CPU를 할당합니다.
명령어 주소 지정:
운영체제는 PCB에서 A 프로세스의 정보를 가져와 CPU의 프로그램 카운터에 실행될 명령어의 주소를 지정합니다.
A 명령어 실행:
CPU는 메모리에서 A 프로세스의 동작에 필요한 명령어를 가져오고, 연산을 수행합니다.
컨텍스트 스위칭 (A → B):
스케줄러에 의해 A 프로세스에서 B 프로세스로 컨텍스트 스위칭이 발생합니다.
PCB 업데이트:
운영체제는 PCB에서 A 프로세스의 정보를 업데이트합니다. (프로그램 카운터 값도 저장)
B 프로세스 정보 로드:
운영체제는 PCB에서 B 프로세스의 정보를 가져와 CPU의 프로그램 카운터에 실행될 명령어의 주소를 지정합니다.
B 명령어 실행:
CPU는 메모리에서 B 프로세스의 동작에 필요한 명령어를 가져오고, 연산을 수행합니다.
컨텍스트 스위칭 (B → C):
스케줄러에 의해 B 프로세스에서 C 프로세스로 컨텍스트 스위칭이 발생합니다.
반복:
위의 과정이 반복되면서 A, B, C 프로세스가 CPU를 공유하며 실행됩니다.
이러한 방식으로 운영체제는 여러 프로세스의 CPU 자원을 효율적으로 관리하며, 각 프로세스의 PCB를 통해 실행 상태와 정보를 추적합니다. 컨텍스트 스위칭을 통해 CPU는 각 프로세스를 빠르게 교대로 실행하여 사용자에게 다중 작업을 수행하는 것처럼 보이게 합니다.
컨텍스트 스위칭 Context Switching
CPU가 하나의 프로세스를 실행하다가 다른 프로세스를 실행하기 위해 현재 실행 중인 프로세스의 상태를 저장하고, 다음 프로세스의 상태로 교체하는 작업입니다.
이 과정에서 프로세스의 제어를 원활하게 유지하기 위해 프로세스 제어 블록(PCB)의 내용(프로세스 상태, 다음 실행할 명령어의 주소를 담고 있는 프로그램 카운터, 각종 레지스터 값, 메모리 관련 정보)이 변경됩니다.
컨텍스트 스위칭 과정
CPU 점유 시간 초과:
프로세스 A가 CPU를 사용하는 동안 할당된 점유 시간을 초과합니다.
인터럽트 발생:
운영체제는 프로세스 A가 CPU를 너무 오랫동안 사용했다고 판단하고 인터럽트를 발생시킵니다.
상태 저장:
프로세스 A는 현재 실행 중인 작업을 중지하고, 현재 CPU의 레지스터 값과 상태를 PCB A에 저장합니다.
프로세스 B 상태 설정:
PCB B를 참조하여 이전 프로세스 B의 상태로 CPU의 레지스터 값을 설정합니다.
PCB B에는 다음에 실행할 명령어의 주소를 포함하는 프로그램 카운터가 저장되어 있습니다.
프로세스 B 실행:
CPU는 프로세스 B의 명령어를 실행할 준비가 완료되며, 즉시 실행을 시작할 수 있습니다.
다시 인터럽트 발생:
프로세스 B가 점유 시간을 다 사용하면, 운영체제는 또 다시 인터럽트를 발생시킵니다.
상태 저장 및 교체:
프로세스 B의 상태를 PCB B에 저장하고, PCB A에서 프로세스 A의 상태를 가져와 다시 프로세스 A를 실행합니다.
컨텍스트 스위칭 발생 이유
컨텍스트 스위칭이 발생하는 이유는 여러 가지가 있습니다:
CPU 점유 시간 초과: 프로세스가 할당된 CPU 점유 시간을 초과했을 때.
I/O 요청: 프로세스가 입출력 작업을 요청하여 대기 상태로 전환될 때.
다른 종류의 인터럽트: 시스템의 다른 요구사항이나 이벤트로 인해 발생하는 인터럽트가 있을 때.
스와핑 (Swapping) vs 컨텍스트 스위칭 (Context Switching)
스와핑과 컨텍스트 스위칭은 모두 운영체제가 프로세스를 효율적으로 관리하기 위한 기법이지만, 사용되는 상황과 방법이 다릅니다. 스와핑은 주로 메모리 관리와 관련되어 있으며, 컨텍스트 스위칭은 CPU 자원의 효율적 분배와 관련되어 있습니다.
스와핑 (Swapping)
정의: 스와핑은 메모리 관리 기법 중 하나로, 운영체제가 프로세스를 메모리에서 디스크(스왑 공간)으로 이동시키는 작업입니다. 프로세스가 필요하지 않을 때 메모리에서 제거하고, 다시 필요할 때 다시 메모리로 로드합니다.
목적:
메모리 공간을 확보하여 다른 프로세스가 실행될 수 있도록 합니다.
물리적 메모리가 제한되어 있는 경우 여러 프로세스의 동시 실행을 지원하기 위해 사용됩니다.
작동 방식:
프로세스가 메모리에서 제거될 때, 해당 프로세스의 모든 데이터와 상태를 디스크에 저장합니다.
나중에 프로세스가 필요할 때, 디스크에서 다시 메모리로 로드합니다.
컨텍스트 스위칭 (Context Switching)
정의: 컨텍스트 스위칭은 CPU가 실행 중인 프로세스의 상태를 저장하고, 다른 프로세스의 상태로 교체하는 작업입니다. 이는 다중 프로세스 환경에서 CPU 자원을 효율적으로 할당하기 위해 필요합니다.
목적:
여러 프로세스 간에 CPU 자원을 공정하게 분배하고, 각 프로세스가 주어진 시간 내에 실행될 수 있도록 합니다.
작동 방식:
현재 실행 중인 프로세스의 상태(레지스터 값, 프로그램 카운터 등)를 PCB에 저장합니다.
다음 실행할 프로세스의 PCB에서 상태를 읽어와 CPU에 로드합니다.
주요 차이점
프로세스의 생성과 종료
프로세스 생성 과정:
1. 사용자 실행: 사용자가 .exe
파일을 더블 클릭하여 프로그램을 실행합니다.
2. 메모리 로드: 운영체제가 해당 프로그램의 코드 영역과 데이터 영역을 메모리에 로드하고, 빈 스택과 빈 힙을 생성하여 공간을 확보합니다.
3. PCB 생성: 이 프로세스를 관리하기 위한 프로세스 제어 블록(PCB)을 만들어 초기화합니다.
위의 프로세스 생성 과정은 운영체제가 부팅되고 0번 프로세스가 생성될 때 딱 한 번만 실행합니다.
0번 프로세스와 자식 프로세스:
0번 프로세스: 운영체제가 부팅되면 0번 프로세스가 생성되고, 나머지 모든 프로세스는 이 0번 프로세스를 복사하여 생성됩니다. 복사가 새로 생성하는 것보다 더 빠르기 때문입니다.
부모-자식 관계: 자식 프로세스는 부모 프로세스인 0번 프로세스의 코드 영역, 데이터 영역, 스택 영역, PCB 내용을 모두 복사합니다. 부모-자식 관계 및 자식 프로세스의 독립적인 실행을 통해 효율적인 메모리 관리와 프로세스 관리를 가능하게 합니다.
exec() 함수 사용:
자식 프로세스의 실행:
fork()
함수로 생성된 자식 프로세스가 부모와 동일하게 실행되지 않도록 하기 위해exec()
함수를 사용합니다.코드와 데이터 덮어쓰기:
exec()
함수를 호출하면 자식 프로세스의 코드와 데이터 영역을 원하는 값으로 덮어써 자식 프로세스는 부모와 완전히 다른 동작을 하게 됩니다.
프로세스 종료:
exit() 함수: 자식 프로세스는 작업이 끝났음을 부모 프로세스에게 알리기 위해
exit()
함수를 호출합니다.exit status: 부모 프로세스는 자식 프로세스의 종료 상태(exit status)를 읽고 자식 프로세스를 정리합니다.
좀비 프로세스:
정상 종료 실패: 만약 부모 프로세스가 자식 프로세스보다 먼저 종료되거나, 자식이 비정상적으로 종료되어
exit
신호를 주지 못하면, 부모가 자식의 exit status를 읽지 못하고 메모리에 남아 있는 상태를 "좀비 프로세스"라고 부릅니다.성능 저하: 좀비 프로세스가 많아지면 메모리를 차지하여 시스템이 느려질 수 있으며, 재부팅을 통해 메모리가 초기화되어 성능이 회복될 수 있습니다.
스레드
운영체제의 작업 처리 단위: 프로세스
운영체제는 사용자가 요청하는 작업을 처리하기 위해 프로세스를 생성합니다.
각 프로세스는 프로세스 제어 블록(PCB)과 메모리에 필요한 코드, 데이터, 스택, 힙 영역을 할당받습니다.
프로세스의 한계
프로세스는 메모리 사용량이 많아 여러 개의 프로세스를 생성하는 것이 비효율적입니다.
각 프로세스가 독립적으로 자원을 사용하므로 메모리 오버헤드가 발생합니다.
스레드의 도입
스레드는 프로세스 내에서 실행되는 작업의 단위로, 여러 개의 스레드가 존재할 수 있습니다.
스레드는 같은 프로세스 내에서 PCB, 코드, 데이터, 힙 영역을 공유합니다. 하지만 각 스레드는 독립적인 스택을 가집니다.
스레드 관리
스레드의 구분을 위해 각 쓰레드에 고유한 스레드 ID를 부여하고, 이를 관리하기 위한 스레드 컨트롤 블록(TCB)도 생성됩니다.
이로 인해 운영체제는 프로세스 내의 스레드를 개별적으로 관리할 수 있습니다.
장단점 비교:
스레드는 프로세스에 비해 메모리 사용이 효율적이고 실행 속도가 빠르며, 적은 오버헤드를 통해 작업을 수행할 수 있는 장점이 있지만, 안정성 측면에서는 프로세스에 비해 취약한 단점을 가집니다.
안전성
프로세스: 서로 독립적이므로 하나의 프로세스에 문제가 생겨도 다른 프로세스에 영향을 주지 않습니다.
스레드: 같은 프로세스 내에서 실행되므로, 하나의 스레드에 문제가 생기면 해당 프로세스 내의 모든 스레드에 영향을 미칩니다.
속도와 자원:
프로세스: 각 프로세스가 고유한 자원을 가지므로, 프로세스 간 통신 시 오버헤드가 크고 속도가 느립니다.
스레드: 스택 영역을 제외한 모든 영역을 공유하기 때문에 오버헤드가 적고, 데이터 공유가 용이하지만 공유 자원에서 동기화 문제를 발생할 수 있습니다.
CPU 스케줄링
CPU 스케줄링 개요
프로그램을 실행시키면 메모리에 프로세스가 생성되고 각 프로세스에는 1개 이상의 스레드가 있습니다. 프로세스들은 CPU를 차지하기 위해 운영체제의 명령을 기다리고 있습니다.
운영체제는 모든 프로세스에 대해 CPU를 할당하고 해제하는 역할을 수행합니다. 이 과정을 CPU 스케줄링이라고 합니다.
스케줄링 고려 사항
어떤 프로세스에게 CPU를 할당할 것인가?: 메모리에 있는 수많은 프로세스 중에서 CPU 사용 권한을 부여할 프로세스를 결정합니다.
CPU를 할당받은 프로세스가 얼마나 오랫동안 CPU를 사용할 것인가?: 현대의 시스템에서는 시분할 처리 방식으로 여러 프로세스가 짧은 시간 동안 CPU를 번갈아 사용하는 방식입니다.
CPU Burst와 I/O Burst
CPU Burst: CPU를 할당받아 실행되는 작업입니다.
I/O Burst: 입출력 작업으로, CPU와는 별개로 수행됩니다.
다중큐
프로세스 상태
1. 생성: 프로세스가 생성되면 준비 상태로 전환됩니다.
2. 준비 상태: CPU를 기다리고 있는 프로세스들은 CPU 스케줄러에 의해 실행 상태로 전환됩니다.
3. 실행 상태: CPU를 할당받은 프로세스는 CPU 사용 시간이 끝나면 다시 준비 상태로 돌아갑니다.
- 입출력 요청: 프로세스가 입출력 요청을 하면 대기 상태로 전환됩니다.
- 작업 완료: 프로세스 작업이 끝나면 완료 상태로 전환됩니다.
큐와 프로세스 관리
준비 상태와 대기 상태의 프로세스는 큐라는 자료구조로 관리됩니다.
큐는 선입선출(FIFO) 방식으로, 먼저 들어온 작업이 먼저 처리됩니다.
프로세스 우선순위와 큐
프로세스가 실행 상태에서 준비 상태로 돌아갈 때, 운영체제는 해당 프로세스의 우선순위를 확인하고 그에 맞는 준비 큐에 넣습니다.
CPU 스케줄러
프로세스 정보가 담긴 PCB는 준비 상태의 다중 큐에 들어가 실행되기를 기다립니다.
CPU 스케줄러는 준비 상태의 다중 큐에 있는 프로세스들 중에서 적절한 프로세스를 선택하여 실행 상태로 전환합니다.
입출력 작업 관리
실행 중인 프로세스에서 입출력 작업이 발생하면, 해당 작업의 종류별로 나뉜 큐에 들어갑니다.
CPU 스케줄러는 이 큐를 참조하여 입출력 작업의 스케줄링을 수행합니다.
스케줄링 목표
리소스 사용률
CPU 사용률: CPU의 효율적인 사용을 극대화.
I/O 디바이스 사용률: 입출력 장치의 사용 효율을 높이는 것.
오버헤드 최소화
스케줄링을 위한 계산이 복잡하거나 컨텍스트 스위칭이 빈번하면 오히려 성능 저하를 초래.
스케줄러는 이러한 오버헤드를 최소화하는 것을 목표로 함.
공평성
모든 프로세스에게 공정하게 CPU를 할당하는 것을 목표로 함.
공정성의 의미는 시스템의 특성에 따라 달라질 수 있음.
처리량
주어진 시간 내에 처리 가능한 작업의 양을 극대화하는 방법을 목표로 함.
대기 시간
작업 요청 후 실제 작업이 시작되기까지의 대기 시간이 짧아야 함.
응답 시간
대화형 시스템에서 사용자 요청에 대한 반응 속도를 중요하게 고려.
응답 시간이 짧아야 사용자 경험이 향상됨.
상반되는 목표
모든 목표를 동시에 최적화하는 것은 어려움.
예: 처리량을 높이기 위해 하나의 프로세스에 CPU를 오랫동안 할당하면 응답 시간이 길어질 수 있음.
반대로, 여러 프로세스에 CPU를 고르게 할당하면 응답 시간이 줄어들지만, 처리량이 감소할 수 있음.
시스템에 따른 목표 설정
목표는 사용자와 사용 환경에 따라 다르게 설정되어야 함. 사용자의 필요와 시스템의 목적에 맞게 조정이 필요함.
스케줄링 알고리즘
FIFO : First In First Out
FIFO 스케줄링은 먼저 들어온 작업이 먼저 나가는 방식입니다.
스케줄링 큐에 들어온 순서대로 CPU를 할당하며, 먼저 들어온 프로세스가 완전히 끝나야 다음 프로세스가 실행될 수 있습니다.
FIFO는 직관적인 스케줄링 방식이지만, 평균 대기 시간이 증가할 수 있는 단점이 있어 현대 운영체제에서는 제한적으로 사용되며, 주로 일괄처리 시스템에서 효과적입니다.
장점
단순하고 직관적: 구현이 간단하고 이해하기 쉬운 방식입니다.
단점
긴 대기 시간: 프로세스의 실행 순서만 변경했을 뿐인데도 평균 대기 시간의 차이가 클 수 있습니다.
성능 차이: 프로세스의 Burst Time에 따라 성능 차이가 심합니다. 긴 작업이 먼저 실행될 경우, 그 뒤에 대기하는 짧은 작업들의 대기 시간이 늘어날 수 있습니다.
비효율적 사용: 입출력 작업이 발생하는 경우 CPU가 대기하는 동안 사용률이 떨어지는 단점이 있습니다.
사용 사례
FIFO 알고리즘은 현대 운영체제에서는 잘 사용되지 않지만, 일괄처리 시스템에서 유용합니다. 여기서는 각 프로세스가 완전히 끝나야 다음 프로세스가 시작되기 때문에 실행 시간이 짧고, 단순한 작업 흐름에 적합합니다.
성능 평가
스케줄링의 성능은 평균 대기 시간으로 평가됩니다.
평균 대기 시간: 여러 프로세스가 실행될 때 이 프로세스들 모두의 대기 시간을 평균한 값으로, 이 값이 낮을수록 스케줄링 효율이 높다고 평가됩니다.
SJF, RR, MLFQ는 다음 주차에서..