728x90
728x90
Thread를 단순하게 사용할 때 문제점
- 스레드는 생성 비용이 많이 든다.
- 스레드를 생성할 때마다 Kernel 레벨의 스레드와 연결해야 한다.
- Kernel의 작업이 필요하다.
- 스레드가 많아질수록 Context-Switching이 더 자주 발생하게 되어 CPU overhead가 증가한다.
→ Thread Pool을 사용하여 문제점을 해결한다.
Thread Pool
스레드를 허용된 개수 안에서 사용하도록 제한하는 시스템을 말한다.
- 스레드의 최대 개수를 제한하고 미리 생성한다.
- 사용자로부터 들어온 요청을 작업 큐에 넣는다.
- 작업 큐에 들어 있는 작업을 스레드 풀의 스레드가 맡아 처리한다.
- 작업이 끝난 스레드는 다시 3번 과정을 진행한다.
장점
- 스레드를 재사용할 수 있기 때문에 새로운 스레드를 생성하는 비용을 줄일 수 있다.
- 사용할 스레드의 개수를 제한하기 때문에 스레드가 무한정 생성되는 것을 방지할 수 있다.
단점
- 최대 개수를 필요 이상의 개수로 설정하면 메모리 낭비가 발생한다.
사용 이유
- 프로그램 성능저하를 방지할 수 있다.
- 다수의 사용자 요청을 빠르게 처리하고 대응할 수 있다.
JAVA에서의 사용 및 최적화
- ThreadPoolExecutor를 제공한다. (ExecuteService 상속)
- maximumPoolSize : 최대 스레드의 개수
- corePoolSize : 최소 필요한 스레드의 개수
- keepAliveTime : 스레드 미사용 시 제거 대기 시간
- corePoolSize 만큼의 스레드로 시작한다.
- 남은 스레드가 없다면 스레드를 바로 추가하지 않고 작업큐가 다 찰 때 까지 큐에서 대기한다.
- 작업큐가 다 차면 스레드의 수를 늘린다.(최대 maximumPoolSize까지)
- keepAliveTime이 지나면 corePoolSize로 돌아간다.
Monitor(모니터)
세마포어에서 발전된 형태로, Mutual Exclusion을 지키기 위한 방식이다.
두 가지 큐를 사용한다.
- entry queue
- critical section에 진입을 기다리는 큐
- mutex에 의해 관리된다.
- waiting queue
- 조건이 충족 되기를 기다리는 큐
- condition variable 에 의해 관리된다.
장점
- 사용하기 쉽다.
- 오류 발생 가능성이 낮다.
단점
- 지원하는 언어에서만 사용 가능하다.
- 컴파일러가 OS를 이해하고 있어야 한다.
작동 방식
- mutex를 사용
- acquire(m)에서 lock을 걸고 release(m)에서 lock을 해제한다.
- lock이 걸려 있다면 다음 스레드는 entry queue에서 대기
- condition variable를 사용
- wait(특정 조건이 충족될 때까지)
- thread가 자기 자신을 condition variable의 waiting queue에 넣고 대기 상태로 전환
- wait시 mutex lock을 풀고 entry queue에서 새로운 스레드가 모니터로 진입하며 lock을 건다.
- 새로 들어온 스레드도 특정 조건이 충족되지 않으면 wait 하게 된다.
- signal
- waiting queue에서 대기중인 스레드 중 하나를 깨움
- broadcast
- waiting queue에서 대기중인 스레드를 전부 깨움
- wait(특정 조건이 충족될 때까지)
JAVA 에서의 사용
- JAVA에서는 모든 객체가 내부적으로 monitor 를 가진다.
- monitor 의 mutex 기능은 synchronized 키워드를 통해 사용한다.
- monitor는 condition variable을 하나만 가진다.
- 동작
- wait
- notify(= signal)
- notifyAll(= broadcast)
Fork-Join
큰 작업을 여러 개의 작은 작업으로 나누고, 처리한 후 결과를 합치는 작업이다. ‘분할 정복’ 알고리즘의 병렬화 버전에 해당한다. 하나의 작업을 작은 단위로 나누어 여러 스레드가 동시에 처리할 수 있게 만든다.
- fork() : 프로세스(작업)을 여러 개로 쪼개서 새롭개 생성하는 작업
- join() : 포크해서 생성된 프로세스/스레드 의 결과를 합치는 작업
- 순차 처리(fork-join을 사용하지 않은 경우)보다 무조건 빠른 것은 아니다.
Work Stealing(작업 훔치기)
fork-join 에서 스레드를 공정하게 분할하기 위한 방법이다.
- 분할 기법이 효율적이지 않았거나, 외부 장애로 인해 스레드 별 작업속도에 차이가 생길 수 있다.
- 한 스레드는 바쁘게 일하는 동시에 다른 스레드는 할 일이 없이 대기하는 상황이 생길 수 있다.
- 각 스레드는 부모 큐에서 가져간 작업들을 내부 큐(inbound queue)에 담아 관리한다.
- 스레드는 서로의 큐에 접근하여 작업을 가져올 수 있다.
- 따라서, 쉬고 있는 큐가 바쁜 스레드의 큐에 가서 큐의 꼬리에 해당하는 작업을 빼앗아 오는 과정을 의미한다.
참고
모니터가 어떻게 동기화에 사용되는지 아주 자세히 설명합니다! 자바에서 모니터는 어떤 모습인지도 설명하니 헷갈리시는 분들 꼭 보세요!
728x90
728x90
'Computer Science > Operating System' 카테고리의 다른 글
가상 메모리(Virtual Memory), 페이징(Paging) (0) | 2023.04.02 |
---|---|
내부 단편화, 외부 단편화 (0) | 2023.04.02 |
Thread Safe(스레드 안전) (0) | 2023.03.08 |
IPC(Interprocess Communication) 프로세스 간 통신 (0) | 2023.03.08 |
Compile(컴파일) (0) | 2023.03.08 |