전체 보기
3️⃣

[운영체제론] Chapter 2.2 Thread(스레드)

작성일자
2022/10/04
태그
SUB PAGE
프로젝트
운영체제론
책 종류
1 more property
목차

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: 해당파일 잇나 체크하는 시스템콜. 파일 없으면 에러

학습테스트