interrupt 별로 어떤 루틴을 처리해야 하는지 적어놓음
컴퓨터시스템 구조의 흐름 알고 있을 것
<Timer>
A, B, C프로그램이 있다고 할 때 세 프로그램이 돌아가면서 써야 공평함. round loading 방식
2번 interrupt가 들어오면
- 정해진 시간이 흐른 뒤 운영체제에게 제어권이 넘어가도록 인터럽트를 발생시킴 => 타이머에서 신호가 왔다고 판단
- 타이머 값이 0이 되면 타이머 인터럽트 발생
- CPU를 특정 프로그램이 독점하는 것으로부터 보호(round robing) -> 스케줄링
=> time sharing을 구현하기 위해 널리 이용
=> 현재 시간을 계산하기 위해서도 사용됨
Memory부분이 ISR
CPU 로 들어가기 전 interrupt line에는 스케줄러가 존재.
스케줄러에 따라 device driver를 작동(?)
device driver가 device controller에게 신호 보냄
device controller
: 작은 CPU라고 보면 됨.
- I/O device controller
: 해당 I/O
: 실제 디바이스와 local buffer 사이
일단 local buffer로 쏴주면 device controller가 I/O 끝났을 대 추출해 CPU로 보냄(인터럽트)
입출력의 수행
모든 입출력 명령은 특권 명령(OS만이 특권명령을 사용할 수 있도록 제한해둠)
사용자
시스템콜: 사용자 프로그램은 운영체제에게 I/O 요청
=> 특권명령이란 시스템콜
DRAM 안에서..
read라는 명령어로 시스템콜 하면
OS로 그 명령어가 옮겨옴
trap(소프트웨어적 interrupt)을 사용하여 인터럽트 벡터의 특정 위치로 이동
read() -> mode bit이 0으로 바뀌면서 모니터 모드 -> 키보드의 인터럽트 벡터 찾아가
-> 키보드의 Interrupt service routine의 2번을 콜 -> 키보드의 device driver에게 키를 읽으라고 요청 -> 실제 키보드로 신호 보내 작업 수행
interrupt당한다는 것은 OS로 넘어간다는 것
interrupt -> CPU 현황 정보(레지스터, program counter)를 save한 후 os로 넘어감 -> CPU 제어를 ISR에게 넘김
(넓은 의미) 인터럽트 중요
하드웨어 인터럽트: 키보드의 'a'를 누른 것과 같은
소프트웨어 인터럽트: 두 종류의 원인(exception, system call)
- Exception(): 오류가 발생했을 때 system call을 부른 것처럼 trap을 발생시켜 정리 작업 수행
- system call(): 커널함수 (read() 와 같은)
ISR: 인터럽트 서비스 루틴의 포인터를 가지고 있다.
harddisk가 인터럽트를 걸면 CPU가 harddisk에 해당하는
동기식 입출력 & 비동기식 입출력
getche() -> read() -> 키보드 콜
키가 들어와야 응답
둘 다 하드웨어로부터 입력을 받을 때 인터럽트 발생
<동기식 입출력(Synchronous call)>
; 하드웨어와 발맞춰(I/O 요청 후 입출력 작업이 완료된 후에야 제어가 사용자 프로그램에 넘어감)
read() 명령어를 거쳐 device driver로 감 -> 키보드 -> 리턴
구현방법1)
I/O가 끝날 때까지 CPU를 낭비시킴
매 시점 하나의 I/O만 일어날 수 있음
구현방법2) 개선
ex. 한글 을 BLOCKED 상태로 만들고 기다리게 함
<비동기식 입출력(Asynchronous call)>
: 하드웨어와 따로
프린터를 예로 들 때
print() 콜하면 다시 user에게 돌아오고
print 완료됐다는 것을 따로 알려줌(이것이 인터럽트 !!)
I/O가 시작된 후 입출력 작업이 끝나기를 기다리지 않고
cpu를 바로 쓰기 때문에
"완료되면 인터럽트로 알려줘. 그 전까지 다른 일 하고 있을게"
DMA(Direct Memory Access)
- 빠른 입출력장치
- CPU의 중재 없이 device controller가 device의 buffer storage 의 내용을 메모리에 블록 단위로 직접 전송
CPU를 통과해 harddisk까지 가면 CPU 낭비
단순 전송이면 CPU 개입이 필요 없잖아. -> CPU가 primary memory(DRAM)에게 harddisk로 바로 쏘고 자신에게 보고해달라고 함
블록 단위로 쏘고 끝나면 인터럽트 발생시켜서 나한테 알려줘.
서로다른 입출력 명령어
메모리에 접근하는 방식으로
메모리는 잠시 숨겨져 있음
0~10000: primary memory
10001~10100: 키보드
10101~10200: disk
10201~10300: 마우스
이부분까지는 조금 설렁설렁 들었음
프로그램의 실행(메모리 load)
: Linus, Window 공통 (중요)
컴파일
-> [File system]A.exe (바이너리 기계어 파일, addressing된 상태)
-> [Virtual memory]각 프로세스의 Code, Data, Stack 만들어짐
-> [Physical memory]DRAM 메모리에 각각 로딩
커널도 일종의 프로세스이기 때문에
* 커널 어드레스 스페이스는 virtual memory의 개념을 쓰지 않고 real address 시스템을 씀(커널은 실제 address를 알고 있어야 하기 때문에)
* 반면.. 프로세스A,B의 address space는 virtual memory의 개념을 씀
- virtual memory
: 실제 공간x 마치 공간이 있는 것처럼 addressing만 수행(물론 가상의 주소)
addressing은 무조건 0번지부터
코드 영역/데이터영역/스택영역
프로세스 A, B가 있고
physical memory(DRAM)에서 A는 1000번지부터, B는 2000번지부터 시작한다고 할 때
address translation에선 A+1000, B+2000
"swapping": harddisk의 영역을 마치 메모리처럼 사용하는 것
=> DRAM 메모리가 부족한 경우 안 쓰는 부분을 하드디스크로 백업해서 DRAM의 공간을 확보함
=> 여러 개의 application 실행 가능
하드디스크를 제2의 DRAM으로 활용하기 때문에 프로세스가 많아질수록 속도가 느려짐
커널 주소 공간의 내용
<code 영역>
DRAM 메모리는 비싸고 공간 한계가 있는데 돌려야 할 프로세스는 많음 => virtual memory
커널이라는 프로그램이 작동
시스템콜, interrupt 처리 코드
자원 관리를 위한 코드:
편리한 서비스 제공을 위한 코드
<data 영역>
프로세스는 살이있는 프로그램
프로세스도 프로그램이기 때문에 관리해줘야
- PCB(Process Control Block)-중요
프로세스와 관련된 정보를 저장하고
프로세스가 잘 돌아가고 있는지 관리, 제어
- CPU 위에 OS가 얹혀 돌아감(code)
공간은 data 영역(ex. CPU를 잠시 쉬게 해야 겠다 등등)
<stack 영역>
A 내부에서 부르면 A의 스택에 쌓이다가 system call(read())하는 순간 kernel 스택(kernel 안의 스택)으로 복사됨
-> 이후 kernel의 코드를 콜하게 될 때는 kernel stack에 쌓이게 됨
A() 콜 -> 사용자 정의 함수
printf() -> 라이브러리 함수
A프로그램(커널모드)이 작동하다가 시스템콜하는 순간(write()가 호출되는 순간) kernel모드로 들어감
<A의 스택의 address space>
: A 사용자 모드일 때(library 쓰는 것까지 포함)
main |
a() |
printf() |
<A kernel stack의 address space>
a.exe -> DRAM 의 code에 정보 저장 DRAM의 kernel
프로세스(살아 있는 프로그램)
CPU
user mode와 kernel mode를 왔다갔다 하면서 진행
프로세스 개념 & 상태
프로세스의 개념
프로세스의 context문맥(프로세스의 일대리라고 보면 됨) - 굉장히 중요
다음은 모두 context에 포함된다.
1. CPU 수행 상태를 나타내는 하드웨어 문맥
- Program counter(중요)
Program counter라는 레지스터는 프로세스의 상태 정보 저장 공간(몇 번째 코드를 사용하고 있는지에 대한 정보 저장)
ex. 2번에서 5번으로 바꾸면 Jump와 같은 기능
- 각종 register
ADD $3, $1, $2
프로세스의 현재 연산 상태를 가지고 있기 때문에
2. 프로세스의 주소 공간
- code
code 대로 프로세스가 진행되기 때문에
- data
global/static variable 저장 => 프로세스 설명해주는 자료가 됨
- stack
system call, malloc 등 저장
3. 프로세스 관련 커널 자료 구조
- PCB
운영체제가 각 프로세스를 관리하기 위해 프로세스당 유지하는 정보
프로세스 하나당 PCB 1개 -> CPU, memory 사용 현황 저장하고 있음
- kernel stack
프로세스의 상태
- Running
: CPU를 잡고 기계어를 수행 중인 상태
- Ready
: CPU 할당을 기다리는 상태
- Blocked(wait, sleep)
: CPU 할당돼도 당장 사용할 수 없는 상태
: I/O 등의 이벤트를 스스로 기다림
ex. I/O device에서 파일 읽어와야 할 때 결과를 기다리는 경우
ex. 키보드 입력을 받아야 다른 명령어를 실행할 수 있을 때
=> 자신이 요청한 event가 만족되면 ready
- Suspended
: 외부적인 이유로 프로세스 수행이 정지된 상태(메모리에 프로세스 너무 많아 정리)
ex. 중기 스케줄러에 의해 메모리에서 out됐을 때
=> 외부에서 resume해주어야 active
- New
: 프로세스가 생성 중인 상태
- Terminated
: 수행이 끝난 상태
<작업 순서>
new -> ready(ready queue에 줄 서있음) -> running(CPU에 들어가면)
harddisk에 작업 요청하면 CPU에서는 running -> blocked 상태(harddisk는 속도가 느리기 때문에)
-> harddisk가 작업 완료 -> CPU blocked -> running 상태로 돌아옴
=> running ready blocked 상태 왔다갔다 함
PCB(Process Control Block)
: 프로세스를 관리하기 위해 OS가 kernel address의 data 부분에 놓음(각 프로세스 당 하나씩)
PCB의 구성요소
1. OS 가 관리상 사용하는 정보
- process state: OS가 지속적으로 모니터링
- process ID: 인덱싱해서 저장해놓음
- scheduling information: FCFS. RR, STF 등등 스케줄링 방식 종류
- priority: 높은지 낮은지, 몇 번째 우선순위인지
2. CPU 수행 관련 하드웨어 값
- program counter
- registers
3. 메모리 관련
Code, data, stack의 위치 정보
4. 파일 관련
Open file descriptors
: 현재 열려 있는 파일에 대한 정보 -> 이미 해당 파일을 오픈하고 있는 프로세스가 있다면 다른 프로세스가 오픈하지 못하도록.
PCB 사용
: context switch할 때 저장/복원 위해 사용
‼️context switch(중요)‼️
: CPU를 한 프로세스에서 다른 프로세스로 넘겨주는 과정
CPU 제어권을 A에게서 빼앗아 B에게 넘기는 상황을 가정해보자.
커널의 data 내, B의 PCB에 B의 이전 상태를 저장하고 있었음
-> A에게서 뺴앗는다면
-> A의 PCB에 PC값과 register값을 저장
-> 제어권을 B에게 넘겨 B의 PCB 복원해 계속 수행
- "context switch 아닌 경우"
: system call -> 끝나면 다시 요청한 프로세스로 복귀
: interrupt
-> 잠깐만 갔다 돌아오는 것이기 때문에 context switch가 아님
- "context switch인 경우"
: CPU 제어권이 다른 프로세스에게 완전히 넘어갈 때
-> 저장/복원 수행해 전환하는 과정이 진행된다.
: I/O 요청 system call -> 오래 걸리기 때문에 다른 프로세스에게 CPU 제어권을 넘겨 효율 추구
: timer interrupt -> 큐에 있는 다른 프로세스에게 할당
==> 1번 경우에도 register 등의 정보는 커널을 위해 업데이트해줘야 하기 때문에 PCB에 저장되어야 하지만
2번(context switch) 경우에는 업데이트 사항 모두 저장해야 하기 때문에 오버헤드 큼.
프로세스 스케줄링 위한 큐
linked list로 구현돼 있다.
ready queue에서 process 떼어 disk에 부착 -> 끝나면 다시 ready queue로 복귀시킴
ex. time slice expired: RR 방식 -> 프로세스 할당 시간이 끝나면 뒤로 보냄
스케줄러
long-term, medium-time은 참고하기만 하고 short-term만 확실히 알 것
<long-term scheduler>
= 장기 스케줄러 = job scheduler
: ready queue에 보낼 것 결정해서 보냄
<short-term scheduler>(중요)
=단기 스케줄러 = CPU scheduler
: CPU에게 어떤 프로세스를 줄 것인지(어떤 프로세스를 running 시킬지) -> CPU 활용도 결정하므로 가장 중요
<medium-time scheduler>
=중기 스케줄러=swapper
: 여유 메모리 확보를 위해 특정 프로세스를 아예 메모리 밖으로 쫓아내기
Thread
CPU util의 기본 단위
: CPU 관련 정보만 -> lightweight process
(중요) thread 구성과 thread가 동료 thread와 공유하는 부분을 구분하기
<thread의 구성>
- program counter
- registers
- stack space
<동료 thread와 공유하는 부분(=task)>
- code section
- data section
- OS resources
<다중 thread>
T1 thread가 blocked 돼도 T2&T3가 실행되어 막힘없이 처리 가능
-> high throughput & 병렬성 증가
프로세스를 여러 개 만들면 되지만 왜 이렇게 할까?
프로세스를 만든다는 것은 주인을 만드는 것과 같기 때문에,
프로세스를 만드는 것은 thread를 만드는 것보다 훨씬 많은 자원을 만들어야 함(PCB, address space등..)
+ 프로세스끼리 호환도 잘 안 됨
=> thread 만드는 게 나음 !!
하나의 프로세스에 여러 개의 thread
-> code, data, OS resource는 공유
-> CPU 수행 관련 부분만 별도로 관리(pc, register, stack)
=> 프로세스 하나여도 여러 개의 프로그램 띄우기 가능
*process와 thread의 차이점을 중심으로 공부하기
<thread 장점>
1. responsiveness(반응성)
T1에 문제가 있어도 T2, T3가 작동하기 때문에
2. resource sharing
process간에는 호환성x
: process1이 키보드에 작업을 요청하면 키보드 응답은 process1에게만 주고 process2에게는 주지 않음
thread간에는 호환성(서로 자원 및 메모리 접근 권한)
3. economy
프로세스 대비 thread 생성 시에는 일부만 생성하는 것이기 때문에 비용 적음
4. utilization of MP(Multicore processor) architectures
: 스레드와 프로세스의 공통적인 특징
: 각 thread는 parallel하게 운영됨
<thread 실행>
아래 쓴 것 정도만 공부할것
- kernel threads: kernel이 지원하는 thread
: windows 95/98/NT
: LINUX
- user threads: library가 지원하는 thread
: POSIX Pthreads
'학교 강의 > 운영체제' 카테고리의 다른 글
[Chapter 4] Process Management (0) | 2025.04.19 |
---|---|
[Chapter 2] System Structure & Program Execution (0) | 2025.04.18 |
[Chapter 1] Introduction to Operating Systems (0) | 2025.04.10 |
[Chapter 5] CPU scheduling (0) | 2025.04.07 |