os수업을 들으며 본인이 정리한 내용입니다.
사용교재 : Operationg System Concepts 10th edition (공룡책)
4단원 : Tread & Concurrency
tread가 필요한 이유 : 여러 개의 task들이 직렬적으로(serialized) 수행할 필요가 없기 때문.
ex) web server : server에 request가 여러개 오면 그때마다 fork함수를 통해 각각의 request를 처리하는 process를 생성 -> fork함수를 여러 번 호출
-> process를 생성하는 것은 resource-intensive하고 time-consuming하다
- fork함수는 부모 함수를 duplication 해야함
- PID, PCB 할당
- 프로세스 통신 위해 IPC mechanism 필요
각각의 process들은 동일한 프로그램을 수행(request를 처리하는 프로그램을 처리) 하므로 code와 data를 각각 가질 필요가 없음 -> 별도로 수행하되, code와 data를 공유하자
multithread model-> 공유할 것은 공유하고, 별도로 가져야 하는 건 공유하지 말자
multi-threaded process
single process는 process 하나당 실행 유닛(thread)이 하나, multi-threaded process는 하나의 process내에 여러 개의 실행 유닛을 포함할 수 있음. code, data, files는 공유하면서 register과 stack은 별도로 가짐.
request가 새로 왔을 때, single process는 process를 생성해야 하지만 multi-threaded process는 thread만 생성하면 됨
장점
1. responsiveness(응답성): 하나의 thread가 block 당하더라도 나머지 thread가 동작할 수 있음
2. resource sharing : code, data, resource를 공유할 수 있음 -> over head를 줄임
3. economy : over head가 큰 process creation과 context-switch를 해결
4. multi-processor 환경에서 효과적 -> 각각의 thread들이 CPU에 할당될 수 있으므로 병렬적으로 수행 가능
multicore programming
여러 개의 thread를 병렬적으로 처리하는 2가지 방법
1. data parallelism : 동일한 operation의 dataset을 분리해서 수행한 후 다시 합침
2. task parallelism : 별도의 operation을 별도의 core에 나눠서 수행
concurrent(동시성, 병행성) -> single-core system
single core : t1, t2, t3, t4, …
parallelism(병렬성) -> multi-core system
core1 : t1, t3, t5,…
core2 : t2, t4, t6,…
multicore programming은 왜 어려울까?
OS :
- core에 할당될 task 명세
- core간의 balance 고려
프로그래머 :
- data splitting: 어떤 task에서 data 처리할지
- data간의 의존성 고려
- testing, debugging 어려움
multi-threading model
-kernel thread : kernel에 의해 생성
-user thread : user에 의해 생성(응용프로그래머에 의해)
user thread가 kernel thread에 mapping 되어있다.
kernel은 user thread의 존재를 모른다. kernel thread의 존재만 알고 있다.
별도로 스케줄링 될 수 있는 개체는 kernel thread이다.
user thread가 disk I/O 하더라도 kernel에서는 mapping된 kernel thread가 한 걸로 알게 됨
따라서 해당 kernel thread가 waiting state에 들어가므로 실제 disk I/O 한 user thread 뿐 아니라 kernel thread와 연결 되어있던 모든 user thread가 전부 block됨.
별도로 수행되는 객체는 kernel thread이므로 CPU에는 kernel thread가 mapping됨. -> user thread와 CPU가 아무리 많아도 kernel thread가 한 개이면 CPU는 한 개밖에 사용을 못함
multithreading model
1. many-to-one : user가 많음, kernel 하나
빠르고, overhead가 적음 -> user thread는 thread library에서 생성, kernel thread 생성은 system call이 필요하므로
단점: 하나의 user thread가 block되면 나머지 다 block됨
병렬적이지 않음 -> CPU하나밖에 못 씀
2. one-to-one : user하나에 kernel하나, 최근에 많이 쓰임 (Linux)
user thread 생성할 때마다 kernel thread 생성 -> 느림, overhead 큼
하나의 user thread가 block되어도 나머지는 계속 work
병렬적임 -> 별도의 CPU에 할당 가능
3. many-to-many : user와 kernel이 모두 많음
scheduler activation : kernel에 의해 user가 block될 때, user를 다른 thread에 매핑해줌 -> upcall이 lwp에게 다른 thread에 매핑할 수 있도록 알려줌
요즘은 복잡한 관계로 잘 사용안함
4. two-level-model = many-to-many + one-to-one
one-to-one모델에 속한 thread를 bound thread라고 부름
Linux의 thread관리법
- one-to-one 모델 사용
- thread가 새로 생성될 때 마다 별도의 PCB(process control block)를 할당해줌
- pthread_create 함수를 호출하여 PCB를 생성함
- 실제 kernel thread는 매핑되지 않고, kernel자체의 일만 함
- fork – process하나에 thread하나
- clone or pthread_create - 각각의 process에 여러 개의 thread (clone은 Linux에서만 쓰임)
thread libraries
-> 사용자가 api를 호출할 때 필요
2가지 방법
1. thread를 생성하는 library 함수를 호출하면 user space에 한정 되어있기 때문에 system call로 연결되지 않음
2. OS로부터 직접적으로 지원받기 때문에 system call의 지원을 받음 -> Linux의 PCB생성
3개의 주요 thread libraries:
1. posix pthreads : kernel과 user level library를 모두 지원-> Linux에서는 kernel level로 지원
2. win32 threads : kernel level library -> one to one model(계속 kernel thread를 생성하므로)
3. java threads : system에 따라 달라짐
사용 예시
1. pthread_attr_init함수를 호출 -> thread의 속성을 설정해줌, 인자값으로 null을 넘기면 default 속성으로 설정됨
2. pthread_create함수 호출 -> pthread 만들기,
pthread_create함수 호출되면 PCB를 생성함
PCB가 생성되면 runner함수가 수행됨
인자에 있는 runner함수는 thread의 실제 코드를 가지고 있음
3. pthread_join -> wait랑 비슷 : runner함수가 끝나기를 기다림
4. runner함수에서 pthread_exit() 함수가 호출되면 wait멈춤
Treading issues
1. thread가 fork함수를 호출할 경우에 해당 thread만 복사할 것인가?
- exec함수가 바로 호출되지 않을 경우에는 전체 process의 모든 thread를 복사한다 -> 프로그래머가 요청한 것이므로,
- exec함수가 바로 호출 될 경우에는 calling thread만 복사하는 것이 유리 -> 어차피 overwrite될 것이므로
2. thread cancellation
asynchronous cancellation : target thread을 바로 종료시킨다.
- ex) 웹페이지를 띄우면 동영상, 광고 등이 같이 뜨는데, 이것들은 모두 별도의 thread로 이루어져 있다. 이때 창을 닫을 경우 target thread들(동영상, 광고 등)도 같이 종료된다.
deferred cancellation : target thread를 바로 종료시키지 않고 미룬다. safe cancellation point(target을 종료시켜도 safe하다고 생각되는 구간)까지 미뤘다가 종료시킨다.
3. signal handling
- process에게 event가 발생된 것을 알려주기 위한 메커니즘
- synchronous signal : 내부적인 문제에서 발생한 exception (ex) 0으로 나누기
- asynchronous signal : 외부에서 발생함 -> (ex) Linux에서 ctrl + c를 누르면 termination됨 -> default signal handler(원래 있는 signal handler)
signal handler : signal을 처리하는 역할
default signal handler : kernel에 구현 되어있는 signal handler
user-defined signal handler : 사용자가 작성한 signal handler
option
1. signal이 해당되는 thread에만 전송 (ex) 0으로 나누는 연산
2. signal이 모든 thread에 전송 (ex) ctrl + c를 누름 -> 전부 종료
3. signal을 특정 thread에게 전송한다.
4. signal이 적용되는 thread를 지정한다. -> pthread_kill(pthread_t tid, int signal)함수 이용 -> tid함수에게 signal을 적용해라
thread pools
- thread를 미리 생성해놓고 가져다 쓰는 개념
- 하나의 process 내에서 제한된 개수의 thread만 생성 가능하게 한다. -> 계속해서 thread를 생성하면 system resource가 지치기 때문
- 빠르게 thread를 생성하기 위해서 pthread_create함수가 호출될 때마다 thread를 생성하는 게 아니라, pool에 여러 개의 thread를 미리 생성해 놓고 가져다 씀
- pool에 thread가 3개 밖에 없으면 4번째 request는 실행할 수 없거나 기다려야 함
-> 빠른 처리가 가능 (creation을 하지 않음)
-> resource exhaust방지(지침)
thread-specific data
특정 thread를 위한 data가 있음 = 각각 thread가 자기만의 data영역을 두고 사용할 수 있음, thread libraries 지원
data는 공유하는 게 원칙이지만 특정 thread를 위한 data가 있음을 허용한다.
posix thread programming
- thread creation
main thread가 pthread_create함수 호출 -> peer thread(runner)가 main과 concurrently 수행되기 시작
- reaping terminated threads
-> main thread가 pthread_join함수를 호출하면 block됨 -> peer thread에서 ptread_exit함수 호출 -> pthread_join 함수에서 return 됨(exit함수에서 넘긴 인자를 pthread_join함수의 두번째 인자로 받을 수 있음)
- terminating the thread
peer thread에서 호출됨, return값을 pthread_join에 넘김
'전공과목 정리 > 오퍼레이팅 시스템 (OS)' 카테고리의 다른 글
OS(6) - process synchronization (0) | 2022.11.14 |
---|---|
OS(5) - process scheduling (1) | 2022.11.13 |
OS(3) - Process (0) | 2021.05.12 |
OS(2) - system 구조 (0) | 2021.05.12 |
OS(1) - OS의 전반적인 소개 (0) | 2021.05.02 |