2022. 10. 28. 22:23ㆍCS/Operating System
운영체제에 대한 개념이 약한 것 같아 대략적으로 전체 흐름을 알려주는 강의를 듣고 정리하는 포스팅을 시작합니다.
강의를 듣고 끝내면 그 당시에는 고개를 끄덕이며 넘어가더라도 시간이 지나면 휘발성이 너무 강하다고 느꼈습니다.
시간이 걸리더라도 하나하나 타이핑 치면서 공부하려고 합니다.
이후 계획 : KOCW에서 이화여자대학교 반효경 교수님의 운영체제 강의를 수강할 계획입니다.
목차
운영체제 개요
운영체제의 역사
운영체제의 구조
컴퓨터 하드웨어와 구조
컴퓨터의 부팅 과정
인터럽트
운영체제 개요
요즘에는 운영체제가 쓰이는 곳이 많습니다.
- 개인용 컴퓨터에는 Windows나 MacOS
- 스마트폰과 태블릿에는 안드로이드와 iOS
- 내비게이션 등 여러 가전제품에는 임베디드
- 대형 컴퓨터나 서버용으로는 유닉스나 리눅스가 많이 쓰이고 있습니다.
그럼 이런 의문이 들 수 있습니다,
" 컴퓨터는 운영체제가 있어야 동작하는가?"
...
답은 없어도 동작한다입니다.
하지만 운영체제가 없으면 처음 설계한 그대로만 동작할 뿐 다른 기능을 추가할 수 없기에 유연성이 떨어지게 됩니다.
(예) 유선 전화기- 전화 수신 발신만 가능 vs. 스마트폰 - 애플리케이션 다운로드도 가능)
운영체제가 관리하는 일
1. 프로세스 관리
우리가 보통 PC를 사용할 때를 생각해보면 인터넷 브라우저를 켜놓고 노래를 들으며 게임까지 동시에 하고 있는데 어떠한 에러 없이 스무스하게 잘 실행됨을 알 수 있습니다.
하지만 만약 운영체제가 프로세스 관리를 하지 않는다면 어떻게 될까요?
브라우저가 CPU를 독차지해서 게임이 실행되지 않거나 반대로 게임이 CPU를 독차지해 노래가 실행되지 않을 수 있게 됩니다.
2. 메모리 관리
모든 프로그램은 메모리에 올라와서 동작합니다.
여기서의 프로그램은 위에서 예로든 인터넷 브라우저, 게임, 음악 플레이어라고 생각하시면 쉽습니다.
오늘날 운영체제는 여러 프로그램을 동시에 실행시키기 때문에 (여러) 프로그램을 메모리에서 관리합니다.
3. 하드웨어 관리
운영체제는 사용자가 하드웨어에 대한 직접적인 접근을 막습니다.
사용자 ↔ 운영체제 ↔하드웨어
사용자가 하드디스크(이게 하드웨어)에 데이터를 저장할 때 하드디스크의 특정 영역에 바로 저장하지 못하게 막고 운영체제가 판단해서 적합한 위치에 저장합니다.
그 이유는 하드디스크의 특정 영역에 이미 중요한 데이터가 있을 수 있고 사용자가 악의적으로 공격할 수 있기 때문입니다.
4. 파일 시스템 관리
하드디스크의 많은 파일들의 효율적인 저장과 관리를 합니다.
운영체제의 역사
부제 : 어떻게 하면 CPU를 놀지 못하게 만들까...
- 1940년도
- 에니악은 미사일 탄도계산을 위해 미군 지위 하 개발된 컴퓨터로
- 명령이 떨어지면 스위치와 배선을 연결해서 프로그래밍을 했기에 시간이 오래 걸림
- 입출력 속도가 굉장히 느리고 입출력 도중에는 계산을 할 수 없음
- 1950년도 초반
- 진공관과 전선으로 만들어진 논리회로인 (아주 작게 만든) 직접 회로(IC)가 개발됨
- 이 당시는 CPU, 메모리는 있지만 키보드와 모니터는 없었음
- 대신 프로그래머가 펀치카드를 뚫어서 프로그래밍을 한 후 컴퓨터가 카드를 읽어 계산 후 프린터로 출력
- 1950년도 중 후반
- 프로그래머가 펀치카드를 뚫어서 프로그래밍을 하면 오퍼레이터가 직접 컴퓨터에 카드를 넣고 결과가 나오면 다시 프로그래머에게 전달하는 방식
- 프로그래머 ↔ 오퍼레이터 ↔ CPU
- 이런 방식은 컴퓨터의 처리 속도보다 오히려 오퍼레이터가 카드를 넣고 전달하는 시간이 너무 큼(오버헤드가 큼)
- 오버헤드(overhead): 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말한다.
- 그래서 프로그래머가 펀치 카드 여러 장을 오퍼레이터에게 가져다주면 여러 개를 한 번에 컴퓨터에 전달해주고
컴퓨터는 여러 개의 프로그램을 순서대로 실행해서 결과도 한 번에 확인할 수 있도록 하였는데
이를 "싱글 스트림 배치시스템"이라고 합니다. - 결과적으로 CPU의 사용률이 올라감
- 그리고 당시에는 입출력 작업을 하는 동안에는 CPU를 사용할 수 없었는데 입출력을 담당하는 I/O 디바이스 컨트롤러를 만들어 입출력 중에도 CPU가 계산할 수 있도록 만들었음
- I/O 디바이스 컨트롤러는 입출력 작업이 끝나면 CPU에게 인터럽트 신호를 주고 인터럽트를 받은 CPU가 이어서 처리
- 싱글 스트림 배치시스템의 한계
- 여기서 한 가지 문제점은 CPU와 입출력을 분리했는데 입력이 전부 완료되어야만 처리를 할 수 있기에 CPU가 기다리게 되어 CPU 사용률 떨어짐 (출력은 CPU가 종속적이지 않기 때문에 기다리지 않음)
- 프로그래머가 펀치카드를 뚫어서 프로그래밍을 하면 오퍼레이터가 직접 컴퓨터에 카드를 넣고 결과가 나오면 다시 프로그래머에게 전달하는 방식
- 1960년도
- 싱글 스트림 배치시스템의 한계를 극복
- 시분할 시스템
- 프로그램을 순서대로 하나씩 실행하는 것이 아니라 메모리에 여러 프로그램을 올려놓고 시간을 잘게 나눠 빠르게 돌아가면서 실행을 시킵니다. 매우 빠르게 번갈아가며 실행하기 때문에 사용자에게는 동시에 실행되는 것처럼 느끼게 합니다. 이러한 시스템을 "시분할 시스템"이라고 합니다. (시간을 분할해서 사용하는 시스템)
- A 프로그램 0.001초 → B 프로그램 0.001초 → C 프로그램 0.001초 → A 프로그램 0.001초 →...
- 시분할 시스템을 도입하니 A 프로그램에서 입력 작업으로 CPU가 더 이상 기다리지 않고 B, C작업을 하기 때문에 CPU의 사용률이 증가했습니다.
- 프로그램을 동시에 여러 개 실행할 수 있으니 여러 사용자가 한 번에 사용 가능하게 되었는데요, 이 말은 하나의 컴퓨터에 여러 대의 터미널을 둬서 결과적으로 여러 사용자들이 여러 터미널로 하나의 컴퓨터에 접근해서 사용 가능했습니다. 각자 컴퓨터를 혼자 쓰고 있는 듯한 효과를 내었습니다.
- 이에 사용자는 파일들을 저장하기 시작했고 이러한 이유로 "파일 시스템"이 등장했습니다.
- C언어로 유닉스(UNIX) 운영체제를 개발 - 멀티프로그래밍, 다중 사용자, 파일 시스템을 구현한 운영체제
- 멀티프로그래밍 : 프로그램을 동시에 여러 개 실행시킴
- 다중 사용자 : 여러 사용자를 지원
- 그런데 여러 프로그램을 메모리에 두고 동시에 실행시키다 보니 메모리 침범 이슈가 생겼습니다.
- 또한 메모리에 프로그램들이 여러 개가 올라가 자신이 어느 메모리 위치에서 실행되는지 모르는 이슈가 생겼습니다. 이는 하드웨어적으로 '베이스 레지스터'를 추가해서 프로그램의 시작 주소를 저장하고 모든 프로그램은 0번지에서 실행한다고 정하는 방식으로 해결하게 되었습니다.
- 1970년도 이후
- 저렴해진 컴퓨터의 가격으로 개인이 소유하기 시작
- 애플의 매킨토시와 마이크로소프트의 MS-DOS가 많이 사용됨
- 저렴해진 컴퓨터의 가격으로 개인이 소유하기 시작
운영체제의 역사와 발전과정을 길게 적었지만 운영체제가 발전하게 된 원동력은
어떻게 하면 비싼 CPU를 놀지 못하게 더 많이 사용하게 할지, 인력 간 낭비되는 시간을 어떻게 줄일지 노력하는 과정에서 발전하게 된 것입니다.
운영체제의 구조
운영체제의 핵심은 커널입니다.
커널은 프로세스와 메모리, 저장장치를 관리하는 핵심점인 기능을 담당합니다.
* 사용자는 운영체제의 커널에 직접 접근할 수없고 인터페이스를 통해서 접근할 수 있습니다.
사용자 → 인터페이스 → 커널
인터페이스는 GUI, CLI로 나눌 수 있습니다.
GUI(Graphic User Interface)는 그래픽으로 커널과 상호작용
CLI(Command-Line Interface)는 유닉스나 리눅스 같은 운영체제가 기본으로 제공하는 인터페이스로 텍스트를 이용해 커널과 상호작용합니다
* 애플리케이션은 시스템 콜을 통해서 커널에 접근할 수 있습니다.
애플리케이션 → 시스템 콜 → 커널
사용자나 애플리케이션(프로그램)이 하드디스크에 데이터를 저장할 때 만약 시스템 콜이 없이 직접 접근을 한다면
기존 하드디스크에 있던 중요 데이터를 덮어쓸 수도 있고 A 프로그램이 저장한 데이터를 B 프로그램의 데이터로 덮어쓸 수 도 있습니다
시스템 콜을 이용하면 커널에서 제공하는 Write함수를 사용하게 되는데 그럼 운영체제가 알아서 하드디스크의 빈 공간에 저장하게 됩니다.
* 하드웨어와 커널의 인터페이스로는 드라이버를 사용합니다.
하드웨어 → 드라이버 → 커널
운영체제는 많은 종류의 하드웨어를 전부 지원해야 하지만 각각의 하드웨어에 맞는 프로그램을
커널이 미리 전부 가지고 있기는 힘듭니다. 그래서 보통 하드웨어를 제작한 제조사에서 드라이버를 만들어 제공합니다.
컴퓨터 하드웨어와 구조
오늘날의 대부분 컴퓨터는 프로그램 내장 방식의 폰 노이만 구조를 하고 있습니다.
폰 노이만 구조
- 예전에는 에니악과 같이 하드웨어로 프로그램을 만들었기 때문에 프로그램이 달라질 때마다 매번 조정을 해야 했습니다.
- 이를 해결하고자 CPU와 메모리(RAM)를 버스로 연결합니다. (CPU ↔ 버스 ↔ 메모리)
- 버스란 데이터를 전달하는 통로입니다.
- 프로그램은 메모리에 올려 실행시키는데 프로그램을 메모리에 내장했다고 해서 "프로그램 내장방식"이라고 합니다.
오늘날의 컴퓨터 하드웨어
- 가장 중요한 것은 메인보드로 다른 하드웨어들을 연결하는 장치입니다.
장치 간 데이터를 전송하는 건 메인보드의 버스가 담당합니다.
- 메인보드에 CPU, 메모리, 하드디스크, 그래픽카드, 모니터, 마우스, 키보드, 스피커를 연결합니다.
CPU(Central Processing Unit, 중앙처리장치) 구조
CPU를 구성하는 3가지 장치
- 산술 논리 연산장치
- 실제로 데이터 연산을 담당
- 제어 장치
- 모든 장치들의 동작을 지시하고 제어하는 장치
- 레지스터
- CPU 내에서 계산을 위해 임시로 보관하는 장치로 변수라고 이해하면 쉽습니다.
메모리 종류
메모리는 크게 2가지로 나눌 수 있습니다.
- RAM(Random Access Memory)
- 랜덤으로 데이터를 읽어도 저장된 위치와 상관없이 읽는 속도가 같습니다.
- 전력이 끊기면 데이터를 다 잃기 때문에 메인 메모리로 사용합니다.
- ROM(Read Only Memory)
- 반면, ROM은 전력이 끊겨도 데이터를 계속 보관할 수는 있지만 데이터를 한 번 쓰면 수정이 불가능합니다.
- 그래서 컴퓨터 부팅과 관련된 바이오스를 저장하는 데 주로 쓰입니다.
컴퓨터의 부팅 과정
사용자가 컴퓨터를 켰을 때 일어나는 과정을 살펴보겠습니다.
전원을 누르면 →
ROM에 저장된 바이오스가 실행됩니다 →
바이오스는 전원, CPU, 메모리(RAM), 키보드, 마우스, 하드디스크 등 주요 하드웨어에 이상이 없는지 체크합니다. →
만약 주요 장치에 이상이 있다면 오류음을 내면서 부팅이 이뤄지지 않고 →
이상이 없다면 하드디스크에 있는 마스터 부트 레코드에 저장된 부트로더를 메모리로 가져와서 실행합니다. →
만약 윈도우즈 운영체제와 리눅스 운영체제가 둘 다 설치되어있는 컴퓨터라면 어떤 운영체제를 실행할지 선택하는 화면이 나옵니다 (예) Windows10 vs. Ubuntu) →
운영체제를 선택했거나 운영체제가 하나면 바로 운영체제를 메모리로 불러오고 모니터에 우리에게 익숙한 바탕화면이 보이게 됩니다. →
이제부터 시작되는 모든 응용프로그램은 메모리에 올라와서 운영체제가 관리합니다.
인터럽트
CPU가 입출력 장치(키보드, 마우스, 프린터 등)에 데이터를 읽거나 쓰려고 하는 상황을 가정해보겠습니다.
- 폴링(Polling) 방식
- CPU는 입출력 작업이 들어오면 입출력 관리자에게 입출력 명령을 내립니다.
- 그런데 CPU관점에서 입출력 명령이 언제 완료될지 알 수 없기에 주기적으로 확인이 필요합니다.
- 단점: 주기적으로 CPU가 이처럼 확인을 해줘야 해서 성능이 좋지 않습니다.
- 인터럽트
- 폴링 방식의 단점을 해결한 방식
- CPU가 입출력 관리자에게 입출력 명령을 내린 후 다른 작업을 계속합니다.
- 입출력 관리자는 입출력이 완료됐을 때 CPU에게 신호를 주고 CPU는 신호를 받아 인터럽트 서비스 루틴(ISR)을 실행시켜 작업을 완료합니다.
- 인터럽트 서비스 루틴은 특정 인터럽트가 들어오면 그 인터럽트를 처리하는 함수로 비동기적으로 동작하기 때문에 성능에 이점이 있습니다.
- 인터럽트는 하드웨어 인터럽트, 소프트웨어 인터럽트가 있습니다.
- 하드웨어 인터럽트 : 위에 언급한 것처럼 입출력 등과 같은 인터럽트
- 소프트웨어 인터럽트 : 사용자 프로그램에서 발생한 인터럽트
- 예) 유효하지 않은 메모리에 접근하거나 0으로 나누는 명령어 사용
출처: