Thread
Process: 운영체제가 관리하는 기본 단위
Thread: CPU를 활용하는 기본 단위
모든 프로세스는 하나 이상의 Thread로 구성된다.
기본적으로 프로세스처럼 ID, PC, Register, stack 등을 갖는다.
다만 프로세스와 달리 Code section이나 Data section 등이 같은 프로세스 내의 모든 thread가 공유할 수 있다.
프로세스보다 더 가볍다는 장점이 있다.
어떤 작업을 여러 스레드로 나눠서 구현할 경우 관리가 더 용이하다.
Ex) Multithreaded server
Single thread라면 여러 client가 동시에 요청했을 때 먼저 요청된 것부터 하나씩 처리하므로 response time이 길어진다.
Multithread라면 서버가 직접 요청을 처리하지 않고 요청을 처리하는 thread를 만들어 넘긴 후 요청을 받는다.
즉 클라이언트의 요청이 들어올 때마다 그 클라이언트의 요청을 처리할 thread를 만들어 요청을 넘긴다.
-> 각 thread가 클라이언트와 연동되어 동작하므로 response time이 짧아지고 프로그램이 더 modular해져 관리가 쉽다.
Multi process
각 프로세스가 독자적으로 code section, data section을 갖는다.
-> 데이터 공유를 위해 Message passing 등이 필요하다.
각 프로세스 별로 메모리 공간이 필요하므로 메모리를 많이 차지한다.
Multithread
Code section, data section을 공유하므로 Message passing 등의 절차가 불필요하다.
각 프로세스 별로 메모리 공간이 필요하므로 메모리를 많이 차지한다.
=> 응답속도도 빠르고, 더 경제적이며 확장성도 좋다.
Multicore(Multiprocessor)
CPU가 여러 개의 Core로 구성된다. 각 Core에는 실제 processing에 필요한 entity(stack 등)가 존재한다.
-> 각 Core는 프로그램을 실행할 수 있는 단위 = 병렬처리가 가능
이런 환경에서는 동시에 실행할 수 있는 Core를 고려해서, 즉 Multithreaed program을 짜야 한다.
Parallelism: 여러 개의 프로세스가 물리적으로 동시에 실행하는 것 = 주어진 한 순간에 여러 개가 실행되고 있어야 함
Concurrency: 한 순간에는 하나만 실행, 어쨌든 여러 개의 프로세스가 '돌아가고 있는 상태'면 됨
주어진 한 순간에 여러 개가 실행되고 있으면 둘 다 충족
Data parallelism: Data를 여러 개의 core에 분배
Task parallelism: Task(thread)를 여러 개의 core에 분배
Multi-core system에서는 Multithread로 프로그램을 구성해야 효율적이다.
User threads vs. Kernel threads
User space에서 동작하는 thread, Kernel space에서 동작하는 thread
두 공간 사이에 Mapping이 필요하며 다음의 세 가지 mapping model이 있다.
Many-to-One model
Many user thread -> single kernel thread
User thread $U_1,\; U_2,\; U_3,\; U_4$에 대해 Kernel thread가 하나 뿐이면
$U_1$가 blocking 하는 syscall 요청 시 Kernel thread는 $U_1$의 요청만 수행하게 돼서
나머지 User thread는 요청할 수 없게 된다(blocking 된다).
One-to-One model
User thread를 그 수 만큼의 Kernel thread를 각각 하나씩 mapping한다.
$U_1$은 $K_1$에, $U_2$는 $K_2$에 mapping 되는 것이다.
Resource가 많이 소요되지만 blocking은 없다.
Many-to-Many model
앞의 둘을 섞은 것.
다수의 User thread를 다수의 Kernel thread에 한꺼번에 mapping 한다.
-> $K_1$이 $U_1$의 요청을 받아 blocking되어도 나머지 Kernel thread들이 다른 User thread의 작업을 수행한다.
물론 User thread가 Kernel thread보다 더 많을 경우 모든 User thread가 blocking을 요청하면 나머지 User thread는 waiting 한다.
Two-level Model
Many-to-Many와 One-to-One을 같이 사용
중요한 User thread는 One-to-One으로, 나머지는 Many-to-Many로 mapping한다.
-> 중요한 User thread가 blocking되는 것을 방지할 수 있다.
Thread library
User space에서만 구현할 수도 있고 OS에서 제공하는 Kernel-level library를 사용해서 구현할 수도 있다.
PThread(POSIX Library)
API 표준만 제공함: 'PThread와 관련된 API는 이런 게 있다'까지만 제공
-> 각 시스템 별로 내부 구현은 달라질 수 있다
PThread를 쓴다 = 표준화된 API를 쓴다
-> PThread를 제공하는 시스템에서는 API가 다 똑같다(내부 구현은 어떻게 돼 있는지 몰라도)
Java Thread
JVM에 서 제공하는 Thread 사용
JVM은 Host OS에서 제공하는 Thread model 사용
Threading issues(Design issue)
$fork()$ syscalls
어떤 프로세스 내에 4개의 thread가 있다고 하자.
이 중 한 thread에서 $fork()$ 호출 시 어떻게 새 프로세스를 생성할 것인가?
ⓐ 호출한 thread만 포함된 프로세스
ⓑ 4개의 thread가 모두 포함된 프로세스
일부 UNIX는 두 버전의 fork를 지원함
$exec()$ syscalls
어떤 프로세스 내에 4개의 thread가 있다고 하자.
이 중 한 thread에서 $exec()$ 호출 시
ⓐ 호출한 thread의 메모리 공간만 바꾼다
ⓑ $exec()$를 호출한 프로세스 전체의 메모리 공간을 바꾼다.
*$fork()$ vs. $exec()$
$fork()$: 새로운 프로세스를 위한 메모리를 할당한다.
$exec()$: 새로운 프로세스를 위한 메모리를 할당하지 않고, $exec()$에 의해 호출된 프로세스만 메모리에 남는다.
Signal Handling
Signal: UNIX에서는 운영체게가 프로세스에게 Alarm을 줄 때 사용
Ex) Ctrl+C를 누르면 OS가 Process에게 Kill이라는 Signal 전달
① 어떤 이벤트에서 Signal 발생
② 프로세스에 전달
③ 프로세스는 다음의 두 signal handler 중 하나를 갖는다.
ⓐ Default signal handler: 보통은 signal을 무시하거나 kill함
ⓑ User-defined signal handler: 사용자가 신호를 어떻게 처리할지 정의해둠 -> 여기서 issue 발생
프로세스에 여러 개의 thread가 있을 경우 다음의 선택지가 있다.
ⓐ 신호를 어느 thread로 보낸다.
ⓑ 모든 thread에 다 보낸다.
Thread cancellation
A가 B를 종료시킬 떄 어떡할까
무조건 종료
주기적으로 체크해서 종료가 될 때 종료될지
종료 모드는 어떻게?
Thread-Local Storage
전역변수는 모든 thread가 공유하는 문제가 생긴다.
장점도 되지만(데이터 공유) 단점도 됨(thread 별로 전역변수를 가질 수 없다)
각 thread가 독자적으로 가질 수 있는 데이터 저장공간을 어떻게 설정할 것인가?
스레드 별로 static 데이터를 만들 떄 어떡할까?
Scheduler Activations
User thread와 Kernel thread 간의 communication을 어떻게 할까?
User thread와 Kernel thread가 있을 때
User level에서는 User thread를 scheduling 할 때 LWP(LightWeight Process)라는 entity를 대상으로 scheduling을 한다.
User process가 있으면 그를 위해 OS가 여러 개(여러개의 user thread에 하나씩)의 LWP를 할당하고, 각 user thread들을 LWP에 스케줄링하게 된다.
LWP는 Kernel thread와 1:1로 mapping된다.
따라서 Kernel thread가 blocking call을 하면 그 LWP는 사용할 수 없게 되는데, 그걸 알려주기 위해 Upcall을 쓴다.
각 LWP에 있는 Upcall handler를 호출해서 Kernel thread로부터 받은 정보를 User thread로 전달
Summary
Thread: CPU 할당 단위(The basic unit of CPU utilization)
Kernel thread와 User thread가 있고 그의 mapping을 위한 4가지의 model이 있다.
'강의노트 > 운영체제' 카테고리의 다른 글
[운영체제] 4주차: CPU scheduling (0) | 2021.03.29 |
---|---|
[운영체제] Term project: Nachos (0) | 2021.03.28 |
[운영체제] 3주차: Review (2) (0) | 2021.03.22 |
[운영체제] 3주차: Review (1) (0) | 2021.03.22 |
[운영체제] 2주차 (3) (0) | 2021.03.14 |