Multithreaded Architecture
- 프로세스 생성은 heavy-weight, 쓰레드 생성은 light-weight 하다.
- 단일 응용 프로그램이 여러 개의 작업을 동시에 실행할 필요가 있을 때 thread 를 사용한다.
- word processor: 화면 출력 + 키보드 입력 + 스펠링 검사
- web browser: 화면출력 + 네트워크에서 데이터 수신
- web server: 여러 개(수천 개도 가능)의 client의 요청 처리
- OS kernel: 장치 관리, 인터럽트 처리 등의 여러 작업
하나의 웹 서버 프로세스가 외부로부터 요청을 받는 하나의 다수의 클라이언트를 담당하는 thread 들로 이루어진다.
-> 클라이언트로부터 서비스 요청이 들어오면 대기하고 있던 쓰레드가 요청을 받는다.
-> 요청을 받아서 이를 처리할 수 있는 서비스 thread 를 생성하고 요청에 대한 처리를 넘긴다.
-> 서버는 또 다른 클라이언트 요청을 반복해서 기다린다.
Benefits of Multithreading
- Responsiveness : 응용프로그램의 일부가 block 이 되거나, 긴 작업을 수행하더라도 프로그램의 다른부분의 수행이 계속 되도록 허용 -> 응답성 증가
- Resource Sharing : thread 끼리 메모리와 자원을 공유한다.
- Economy : thread 생성은 process 생성보다 비용이 적게 든다.
- Scalability : multithread 는 각 thread 가 다른 cpu 에서 병렬로 수행될 수 있다.
Multicore Programming
multicore 또는 multiprocessor system 은 다음과 같은 것들을 프로그래머들에게 요구한다.
- Task dividing
- Load balancing
- Data splitting
- Minimizing data dependency
- Testing and debugging
- Parallelism
시스템이 여러 개의 task 를 동시에 병렬 실행시킬 수 있다.
- data parallelism : 전체 data 집합을 다수의 부분집합으로 나누고, 이를 다수의 core 에 분배해서 코어가 동일한 연산을 각각 실행하는 경우
- task parallelism : 각 thread 가 서로 다른 작업을 한다.
- Concurrency
여러 개의 task 가 모두 진행한다. (실제로 동시에 실행되는 것이 아니라 cpu burst 를 나눠서 수행)
Amdahl's Law
순차실행을 해야하는 구성요소와, 병렬실행을 해야하는 구성요소를 동시에 가지는 프로그램이 있을 때, 이것을 멀티코어에서 실행했을 때 얼마나 성능 향상이 되느냐에 대한 공식이다.
S : 순차 실행 요소 비율
1-S : 병렬 실행 요소 비율
N : 프로세서 개수
예) 이 프로그램이 75%의 병렬실행이 가능할 때, S = 0.25 이다.
코어가 1개일 때는 speedup <= 1
코어가 2개일 때는 1.6 배의 성능향상 효과를 얻는다.
-> 코어갯수를 늘리면 성능이 향상되지만, 물리적인 한계가 있다.
User Threads and Kernel Threads
- User threads : 커널의 지원 없이 사용자 수준(커널 위) 에서 thread library 에 의해서 지원된다.
- thread library 는 다음과 같다.
- POSIX Pthreads
- Windows threads
- Java threads
- Kernel threads : OS 커널에서 직접 지원되고 관리된다.
예) Windows, Solaris, Linux, Mac OS X
- 사용자 thread 와 커널 thread 간에는 다음과 같은 연관 관계가 존재한다.
- Many to One
- One to One
- Many to Many
Many-to-One Model
- 다수의 user-level-thread 가 한 개의 kernel thread 에 연관된다.
- thread 스케쥴링과 동기화가 사용자 공간의 thread library 에서 수행된다.
- 장점 : context switching 과 동기화 overhead 가 작아서 효율적이다.
- 단점 : 하나의 thread 가 blocking system call 을 호출하여 block 되면 전체 process 가 block 된다.
-> 커널이 user level thread 의 존재를 알지 못하기 때문이다. 따라서 multiprocessor 시스템에서 thread 들의 병렬 실행이 불가능하다.
One-to-One Model
- 각 user-level thread 가 한 개의 kernel thread 에 연관되는 것으로, 요즘 대부분 사용되는 기법이다.
- user-level thread 를 하나 만들면 그에 대응하는 kernel thread 가 생성된다.
- 장점 : 더 많은 병행 실행, 병렬 실행이 가능하다. 한 thread 가 blocking system call 을 호출하여 block 되면 커널은 같은 process 의 다른 thread 로 스케줄링된다.
- 단점 : thread 생성 및 context overhead 가 발생한다. 또한, 커널에서 thread context switching 이 이루어지고, 많은 수의 커널 thread 가 생성시 시스템에 부담이 될 수 있다.
Many-to-Many Model
- 다수의 user-level thread 가 다수의 kernel thread 에 연관되는 것이다.
- 이때 kernel thread 의 수는 user-level thread 의 수보다 작다.
- 운영체제는 충분한 수의 커널 스레드를 생성하고, 원하는 수 만큼의 사용자 스레드가 생성된 후 이들에 대응하는 커널 스레드들이 다중 처리기에서 병렬로 수행될 수 있다.
-> 다대일과 일대일의 장점을 취한 접근법이다.
Two-level Model
many-to-many 모델의 변형모델로, 일부 user-level thread 에 대해서는 one-to-one 연관을 허용한다.
lightweight process 가 user thread 와 kernel thread 간의 중개 역할을 수행한다.
Thread Library : Pthreads
- pthread_create() - thread 생성
- pthread_join() – thread 종료를 기다림
- pthread_exit() – thread 종료
- pthread_attr_init() – thread attribute를 default 값으로 초기화
Java Threads
- Thread 생성 방법
- Extending Thread class (파생 클래스 생성)
- Implementing the Runnable interface (인터페이스 구현)
Thread Pools
- multithreaded server 에서의 잠재적 문제점
- thread 생성 오버헤드 -> 요청마다 thead 를 생성하는 데 시간이 소요된다.
- thread 수 증가에 따른 자원 고갈 가능성 -> thread 수에 제한이 필요하다.
-> 해결책 : Thread Pool
- 프로세스를 시작할 때에 일정한 수의 thread 들을 thread pool 에 미리 생성하여 대기한다.
- 요청을 받을 때마다 pool 에 있는 한 thread 를 깨워서 사용한다.
OpenMP
- 공유 메모리 환경의 병렬 프로그램을 지원한다.
- openmp 에서 병렬로 실행가능한 부분을 parallel region 이라 한다.
GCD (Grand Central Dispatch)
- 병렬 섹션을 구분하여 threading 관리를 지원한다.
- 블록 표시 ^{ }
ˆ{ printf("I am a block"); }
-> 이 블록을 dispatch queue 에 넣어 나중에 실행되도록 스케쥴한다. 이 큐에서 블록을 하나씩 꺼내서 해당 블록을 thread pool 에서 꺼낸 가용 thread 에 핟당하여 실행되도록 한다.
- 두 가지 유형의 dispatch queue
- serial : FIFO
- concurrent : FIFO 이지만, 한 번에 여러개를 꺼낼 수 있고 그렇다면 동시에 실행이 가능하다.
Thread Related Issues
fork(), exec() 시스템 호출
exec() -> 기존 스레드들을 모두 무시하고, 새로운 프로그램으로 대체된다.
- process 의 모든 thread 들을 복제 : fork() - no exec 의 경우에 사용 -> 생성된 프로세스는 multi-threaded
- 해당 thread 만 복제 : fork() - exec 의 경우에 사용 -> 생성된 프로세스는 single threaded
시그널 처리
- 시그널은 프로세스에게 어떤 사건이 일어났음을 알리기 위해 사용된다.
- Synchronous signal : 어떤 사건을 처리하기 위해 발생한다.
- Asynchronous signal : 임의 시점에 발생한다.
- 모든 시그널은 둘 중 하나의 처리기(handler) 에 의해 처리된다.
- 디폴트 시그널 처리기 : 시그널마다 기본적인 처리 방법을 정의한다.
- 사용자 정의 시그널 처리기 : 사용자가 시그널 처리 방법을 정의할 수 있다.
Thread Cancellation
- 비동기(asynchronous) 취소: 즉시 target thread를 취소
- 지연(deferred) 취소 : 주기적으로 점검하여 target thread를 취소
- 실제로 스레드 취소는 thread 의 상태에 의존한다.
-> cancellation point 에 도달했을 때만 취소가 일어날 수 있다.
Thread-Local Storage
- thread 자신 만이 접근 가능한 저장공간으로, 특정 thread 에게 고유하게 할당된다.
'운영체제(OS)' 카테고리의 다른 글
Operating Systems 6. Synchronization Tools - (2) (0) | 2021.12.04 |
---|---|
Operating Systems 6. Synchronization Tools (0) | 2021.12.04 |
Operating Systems 10. Virtual Memory - (3) (0) | 2021.12.04 |
Operating Systems 10. Virtual Memory - (2) (0) | 2021.12.04 |
Operating Systems - 10. Virtual Memory (0) | 2021.10.15 |
댓글