목차
1. 스레드 모델
•
CPU에서 수행을 위해 스케줄되는 단위에 따라 나뉨
1) 프로세스 모델 vs. 스레드 모델
•
프로세스 모델
◦
정의) 프로세스 모델에서 하나의 프로세스에 수행의 흐름(thread)은 하나만 존재
◦
resource grouping: address space(text, data, stack segment), open file, child process 등
•
스레드 모델
◦
정의) 스레드 모델에선 하나의 프로세스 환경에 수행의 흐름(thread)이 여러 개.
◦
특징)
▪
다중스레딩(multithreading): 다수의 스레드가 하나의 프로세스에서 수행 가능
▪
스레드는 각각이 스케줄링의 대상이 될 수도 있음(Ready, Block, Running)
▪
경량 프로세스: 프로세스에 비해 관리하는 자원 적음
•
수행의 흐름(thread)과 관련된 자원: program counter, register, stack
◦
program counter: 현재 수행중인 명령어의 주소
◦
register: 상태
◦
stack: 아직 return되지 않은 함수의 return address, local variable
◦
자원
▪
Per process items
•
한 프로세스 내 모든 스레드가 공유하는 항목들
▪
Per thread items
•
각 스레드들이 개별적으로 보유하는 항목들
◦
각각의 스레드는 본인의 stack 가짐
▪
스레드마다 실행흐름 다 달라서 콜하는 procedure도 다 다를 수 있어서 고유의 스택 필요함
◦
스레드 관련 라이브러리 프로시저
▪
thread_create
•
인자로 만들어진 스레드가 수행할 procedure 줌
▪
thread_exit
•
스레드가 자신의 일 마치고 종료할 때 콜함
▪
thread_wait
•
wait의 대상이 되는 상대방 스레드가 exit할 때까지, 콜한 스레드는 block.
•
서연이가 기우에 대해 thread_wait(기우) call 하면 기우가 종료될 때까지 서연이는 block
▪
thread_yield
•
콜한 스레드는 CPU를 다른 스레드 수행할 수 있게 양보하고 ready로 감
•
mutex에서 등장 (mutex가 언락이면 thread 양보하고 ready 맨끝으로 감. 언젠가 다시 running되면 mutex 또 검사함. 또 언락이면 반복함. 언락이 아니라면 return되어서 임계구역 들어감.
•
프로세스와 스레드 예시
◦
(a) 프로세스 모델: 각기 하나의 스레드 가지는 세 개의 프로세스
▪
세 개 프로세스는 서로 관련 없음
◦
(b) 스레드 모델: 세 개의 스레드 가지는 하나의 프로세스
▪
세 개 스레드는 같은 job의 부분이라 서로 긴밀히 협조함.
▪
세 개 스레드는 자원(ex. address space)을 공유함
▪
세 개 스레드는 협조하게 코딩되어 있어 서로 간에 protection 필요하지 않음.
2. 스레드의 사용
•
스레드를 사용하는 이유
◦
응용프로그램 속에서 여러 개의 activity가 동시에 일어나는 경우 많음
▪
워드 프로시저의 경우 세 개 activity가 동시에 일어남. 세 activity 각각을 하나의 thread로 매핑시키면 프로그래밍 하기 쉬워짐
◦
스레드가 프로세스보다 create, distroy가 쉬움
▪
프로세스 생성하려면 여러 자원들 만들어줘야해서 시간 오래 걸리는데, 스레드는 필요 없음
◦
프로세스 성능 이득
▪
어떤 일 처리하는데 여러 스레드로 구현해두어 한 스레드가 block되어도 같은 프로세스의 다른 스레드들이 cpu 사용하면 프로세스의 성능이 좋아진 것임
◦
각 스레드가 각각의 CPU에서 수행되면 진정한 병렬이 가능해짐
예시) 워드 프로세서
예시) 멀티 스레드 웹 서버
3. 사용자 공간에서 스레드의 구현
1) 스레드 구현 방법
1.
user space에서 thread 구현
2.
kernel에서 thread 구현
2) user space에서 thread 구현
•
유저 레벨 스레드
•
정의) 스레드가 Run-time system에서 수행
◦
커널은 스레드 존재를 모르고, 프로세스만 스케줄링함.
◦
Run-time system: 스레드 관리하는 프로시저 모음
▪
thread_create, exit, wait, yield
•
특징)
◦
스레드테이블을 run-time system이 관리
▪
스레드가 유저스페이스에서 관리됨
◦
각 프로세스는 자신만의 스레드 테이블 가짐
•
장점) [중요]
1.
user level thread는 thread 지원하지 않는 os에서도 구현이 가능함
•
커널이 스레드 존재 모르고, os는 스레드를 지원하지 않아도 유저 레벨 스레드는 유저 레벨에서 thread package 구현하기에 문제 없이 사용 가능
2.
thread switching이 kernel level thread보다 빠름
•
커널 레벨 스레드는 커널이 직접 스레드 스케줄링하기 때문에 커널에 한 번 들어가서 스레드 스위칭 일어나는데 시간 많이 걸림
•
유저 레벨 스레드는 스레드 스위칭이 커널로 안들어가고 일어나서 빠름
•
ex) 서연이가 기우가 일 마칠 때까지 block되려하면, 시스템콜하는 게 아니라 thread_wait(run-time system의 procedure) 콜함. 따라서 run-time system이 wait 콜한 스레드 block으로 놓고 ready상태의 스레드를 running으로 올림
3.
[참고만] 각각의 프로세스가 자신만의 customized된 스케줄링 알고리즘 가질 수 있음
4.
[참고만] 스케일이 더 잘됨
•
커널 레벨 스레드는 커널이 스레드 테이블 가짐. 얼마나 많은 프로세스가 스레드 만들지 모름. 스레드 얼마나 많이 존재할지 모르니 처음부터 스레드 테이블 세팅시 크게 잡아야함. 스레드 세팅 부담됨.
•
유저 레벨 스레드는 프로세스 생길 때마다 그 안에서 스레드 테이블 생기니 스케일 더 잘됨. 딱 맞는 스레드 테이블 세팅 더 용이함. 각자 테이블 관리하고 커널엔 따로 스레드테이블 세팅할 필요 없음.
•
단점)
1.
block 시스템콜 발생 시 문제 생김
•
프로세스의 스레드 세 개 중 하나 수행하다 Read 시스템콜하면 프로세스가 block상태로 감. 스레드가 블록상태로 간건데, 커널 입장에선 프로세스를 통쨰로 block상태로 보냄. 동료 스레드들은 수행기회 못갖게 됨
•
해결 방법 2가지
1.
blocking 시스템 콜을 nonblocking 시스템콜로 바꾸자
•
read 시스템콜이 사용자가 키보드에 아직 입력안해서 block되는건데, 이를 nonblocking으로 코드 바꿈. 커널을 고침.
•
read 시스템콜을 했을 때 키보드 버퍼에 아무것도 없으면 0같은거로 바로 리턴함. block하지 않고. 물론, 마침 사용자가 버퍼에 뭐 넣으면 그거 리턴함. 어떤 경우든 블락 안되게 시스템콜 커널 코드를 고쳐버림.
•
유저 레벨 스레드의 장점이 커널 안해도 되는 거였기에 좋은 해결책이 아님.
2.
wrapper 씌어서 콜했을 때 block될지 미리 체크하자 [참고로만 알기]
•
프로그래머가 read 시스템콜을 할 때, 정확힌 read 라이브러리 procedure를 콜하는 건데, 이 read 라이브러리 procedure를 감싸는 리드를 새로 구현함. 사용자는 이 새로 구현한 wrapper read를 콜함.
•
wrapper read는 read콜하기 전에 select를 콜함. select는 read를 콜했을 때 block이 될지 안될지를 알려줌. block된다하면 read콜안하고 select-illd를 콜해서 cpu를 일단 다른 애한테 넘겨주고 본인은 ready로 감. wrapper 코드는 loop에 있어서 언젠가 다시 running으로 오면 select를 다시 콜해 여전히 block될지 확인함.(버퍼에 뭔가 들어왔으면 block안됨)
2.
프로세스 안(run-time system)에서 clock interrupt 받아 처리하는 건 구현 상 어려움
•
스레드가 어떤 프로세스 속에서 CPU 할당받아 수행하면 스레드가 자발적으로 CPU 넘기지 않는 이상(give up) 그 프로세스의 다른 스레드들은 CPU 차지할 기회 없음
•
프로세스의 quantum 쪼개서 스레드마다 나눠주고 퀀텀 다 차면 clock interrupt 통해 해당 프로세스의 다른 스레드들에게 CPU 주는 것 구현이 어려움
•
한 스레드는 양보안하면 프로세스의 할당량 혼자 다써버릴 수 있음
4. 커널 내부에서 스레드 구현
1) kernel에서 thread 구현
•
커널 레벨 스레드
•
정의) 커널이 스레드 존재를 다 알아서, 커널이 스레드 스케줄링을 함.
•
특징)
◦
스레드테이블을 커널이 관리
▪
스레드패키지를 커널이 관리함
•
장점)
◦
스레드가 block 시스템콜하면 해당 프로세스의 모든 스레드가 블락되는 일 없음
▪
해당 스레드만 block 상태로 보냄.
▪
멀티스레드 웹서버 구현 제대로 가능
▪
nonblocking 시스템콜 요청안해도 됨
•
단점)
◦
커널 들어가야해서 시간 많이 소요됨
5. 하이브리드 구현
•
정의) hybrid(혼합한 것) 커널레벨과 유저레벨을.
◦
커널레벨에서 스레드 제공되는데 커널레벨스레드 하나당 다시 유저 스페이스에서 여러개의 스레드가 매핑되어있음
6. 스케줄러 활성화(activations)
•
정의) user, kernel 레벨 스레드 장점 혼합함
◦
user 레벨 스레드의 장점 수용
▪
유저 레벨에서 스레드 activity(ex. thread wait) 처리함 → 필요 없이 커널 들어가는 걸 피함 (유저 레벨의 장점)
◦
kernel 레벨 스레드의 장점 수용
▪
어떤 프로세스속의 스레드 하나가 read같은 io시스템콜하면 일단 시스템콜햇으니 커널로 들어감.
▪
커널이 프로세스 통째로 block안하고 스레드 존재 알고잇기에(프로세스 a의 스레드 2번이 disk io 요청하는 read 콜한걸 알기에), 이 정보 가져다가 유저 레벨에 있는 런타임 시스템에게 알려줌
•
알려주는 방법: 커널이 유저시스템쪽으로 콜해서 runtime system불러다가 너가 관리하는 프로세스의 어떤 스레드가 리드시스템콜을 했다고 알려줌 (up call)
•
런타임시스템이 스레드를 block상태로 보냄. 커널이 보내는게 아님.
•
시간 흘러 io요청 완료되어 interrupt걸리면 커널이 수행되면서 디스크 리드 요청햇던거 누군지 알기에 커널이 다시 런타임시스템콜에게 이를 알려줌. 그러면, 유저스페이스에 잇던 런타임시스템콜이 블락상태에 보내논 그놈을 레디상태로 올려줌.
▪
io 관련한 리드 시스템콜 발생할지라도 프로세스 전체가 블락될 일 없음. (커널레벨의 장점)
7. 팝업 스레드
•
정의) 메시지가 도착하면 이를 처리하는 새로운 스레드 생성
◦
기존 구조에선 incomming message 처리하는 스레드들이 대기하고 있다가, 메시지 들어오면 결과적으로 블락되잇는 스레드가 레디로 빠지고 interrupt 처리함. 레디에서 러닝으로 갈 때 예전상태 load해줘야하는데 이 reload가 시간 많이 걸림
◦
팝업 스레드는 이거 시간 줄이기 위해 incomming messag 들어왓을때 대기하지말고 스레드 새로 만듬. 새로 만든건 상태 reload할 필요 없음.
8. 단일 스레드 코드를 다중 스레드 형태로 만들기
•
정의) 스레드마다 private한 global 변수 저장하는 부분 만듬
◦
기존 프로세스모델: 스레드 하나
▪
시스템콜 처리중 에러 발생하면 global 변수 errno에 에러 저장됨.
▪
기존 프로세스 모델이 아니라 스레드 모델, 멀티 스레드 생각하면 스레드 두 개 잇을 수 잇음. 둘다 error 값이 errno에 저장됨. 글로벌변수라서 errno값이 overwritten되어버림. 낭패.
▪
access: 해당파일 잇나 체크하는 시스템콜. 파일 없으면 에러