티스토리 뷰

프로세스들을 하나 만들려면 별도의 주소공간을 할당해야하고 PCB(프로세스 테이블의 한 엔트리)를 만들어야 하기 때문에 좀 무겁다.

그렇기 때문에 한 프로세스내에 같은 일이 반복적으로 발생할때에는 쓰레드를 여러개 생성하는게 프로세스를 여러개 생성하는거보다 훨씬 좋다.

퍼포먼스가 향상된다( 어떤 쓰레드는 블럭 되더라도 다른 쓰레드는 여전히 실행이 가능하므로)

또한 쓰레드는 여러개의 씨피유가 있는 환경에서 병렬적으로 동시에 실행될수 있기 때문에 성능이 대폭 향상된다.


만약 워드 프로세서 응용프로그램을 실행중이라고 치자.

사용자로부터 키보드 입력을 받아서 화면에 출력해주는 일이 필요하고, 사용자가 첫 페이지에 한줄을 지웠을때 그 뒤에 입력 되어있던 글들을 앞으로 땡겨주는 일이 또 필요하고, 주기적으로 디스크에 저장을 해야하는 일이 필요하다.


근데 이 응용프로그램에서 위의 세가지 일을 3개의 프로세스로 처리를 하게 될경우보다 1프로세스 안에 3개의 쓰레드를 만들어서 사용하는것이 훨씬 가볍다. (프로세스 스윗칭 보다 쓰레드 스윗칭이 더 빠르고 가볍다)


만약에 1개의 프로세스로 워드프로세서를 실행 시킨다고 했을때 사용자가 첫페이지의 한줄을 지웠을때 리포맷팅하는 작업이 동시에 일어날 수가 없으므로 지우고 나서 800페이지를 보고싶어서 클릭했을때 리포맷팅하는 작업이 그제서야 실행 되기 때문에 반응성이 떨어진다.



웹 서버에서 쓰레드를 활용하는 예를 살펴보자.

Dispatcher Thread라는것은 Worker thread에게 작업을 나눠주는 역할을 하는 쓰레드이다.

a는 Dispatcher Thread의 코드이고 b는 worker thread의 코드이다.


(a)

몇번 페이지를 읽어줘 라는 요청이 buf에 들어가고 그것을 워커쓰레드에게 나눠준다.

(b)

b는 일감을 기다리다가. buf에 일감이 들어왔으므로 캐시에서 일감을 찾아서 page라는곳에 넣는다. 만약에 캐시에 80번페이지의 내용이 없으면 null이 들어가게 될것이다. 그렇게 되면 디스크에서 읽어오라는 명령을 시킨다.

어찌됬건 이쯤되면 page에는 사용자가 요청한 웹페이지의 내용이 들어가있을거고 return_page를 호출하게 된다.



쓰레드의 구현 방법 2가지

유저레벨 쓰레드,커널레벨 쓰레드


유저레벨 쓰레드의 예가 위의 그림이다.


한 프로세스 안에 Run-time system이라는게 들어있고 그안에 쓰레드 테이블이 들어있다.

커널레벨 쓰레드는 쓰레드 테이블을 커널이 관리한다.


쓰레드 관련 라이브러리가 런타임 시스템에 핵심적인 부분이다. thread_create thread_exit thread_yield 등 라이브러리를 사용해서 쓰레드를 생성,종료,양보등의 일을 해준다. 커널은 쓰레드의 존재를 알 수 없고 프로세스의 존재만 알 수 있다. 따라서 커널은 프로세스 테이블만 관리한다.


유저레벨 쓰레드의 장점


1. OS가 쓰레드를 서포트 하지 않아도 상관이 없다.

2. 유저레벨 쓰레드 스윗칭은 커널레벨 쓰레드 스윗칭 보다 가볍고 빠르다.

-> 커널 레벨 쓰레드는 스윗칭을 할때 커널을 들어갔다 나와야 한다(커널에 들어가는걸 trap이라 한다). -> 오버헤드가 있다.

3.각 프로세스 마다 독립적인 쓰레드 스케쥴링 알고리즘을 사용할수 있다.

4.확장성이 더 좋다

-> 커널레벨쓰레드 같은 경우에 처음 쓰레드 테이블을 생성할때 크기를 몇으로 할지 난감하다.

-> 유저레벨쓰레드의 경우에는 프로세스마다 쓰레드 테이블이 있으니까 훨씬 단순하게 관리할수있다.

-> 쓰레드 테이블을 확장해야 하는 경우에도 유저레벨쓰레드가 커널레벨쓰레드 보다 더 쉽게 확장할수있다.


1,2번이 제일 중요한 유저레벨 쓰레드의 장점이다.


유저레벨 쓰레드의 단점

1. 유저레벨 쓰레드가 블락킹 시스템콜을 호출하게 될 경우 그 프로세스 자체가 블락 되므로 그 프로세스 내에 있는 다른 쓰레드 까지 모두 블락됨.

-> 가장 심각한 유저레벨 쓰레드의 단점.

2. 유저레벨 쓰레드를 라운드로빈 스케쥴링을 한다고 했을때, 프로세스마다 퀀텀을 주게 되는데, 한 프로세스에게 할당된 퀀텀을 또 그 내부에 있는 쓰레드 별로 퀀텀을 나눠주어야 하는데, 이런 작업 자체가 복잡한 작업이다.


1번에 대한 해결책

1. 블락킹 read 시스템콜을 호출하지 말고 non-blocking read 시스템콜을 호출해라.

-> read시스템콜을 호출할때 사용자로부터 입력된 데이터가 없으면 블락되게 된다.

-> 블락 되지 않는 non-blocking read시스템콜을 호출하면 된다.

-> 이 시스템콜은 사용자로부터 입력이 들어와 있지 않으면 블럭되지 않고 데이터가 입력 안됬다고 말해주면서 바로 리턴한다.

-> 커널이 non-blocking read 시스템콜을 지원 하지 않을 경우 난감하다.


2. wrapper 메소드를 사용해라.(blocking read 시스템콜 사용)

->blocking read시스템콜을 호출하기전에 select시스템콜을 호출하면 그 바로 다음에 나올 read시스템콜이 블럭 될지 안될지를 알 수있다.

->그래서 아래와 같은 wrapper function을 만들어서 사용해야 한다. 이 함수를 무한루프를 사용해서 계속 read가 블럭될지안될지를 체크후

    버퍼에 데이터가 있을 경우에만 blocking read를 호출

specialread()

{

read시스템콜에 대한 select호출

if(read가 블럭될것이라면)

read호출 금지

else

read호출

}



커널레벨 쓰레드



커널 레벨 쓰레드는 커널이 프로세스 테이블 뿐만 아니라 쓰레드 테이블 까지 관리해주므로 런타임 시스템이 필요가 없다.

유저레벨 쓰레드의 장단점이 커널레벨 쓰레드의 단장점이 된다.


커널 레벨 쓰레드의 장점

1.커널레벨 쓰레드에서는 한 프로세스가 블락킹 시스템콜을 하게 되었을때, trap이 일어나고 쓰레드의 존재를 커널이 알고 있으므로 블락을 시킬때 그 쓰레드만 블락을 시킨다. 그러므로 다른 쓰레드는 영향을 받지 않는다.( 유저레벨쓰레드의 한 프로세스의 모든 쓰레드가 블락되는것과 상반됨)



커널 레벨 쓰레드의 단점

대신에 trap이 일어나야 쓰레드 스윗칭이 가능하므로 유저레벨쓰레드보다 쓰레드 스윗칭이 느리다.


런타임 시스템콜 중에서 thread_yield를 생각해보자. cpu를 다른 쓰레드에게 양보하는 라이브러리인데, 쓰레드 스윗칭이 빠르다.

(유저레벨스레드,커널의 관여 x) -> 이런 경우에 유저레벨쓰레드가 적합하다.

하지만 블락킹 시스템콜을 자주 사용하는 프로그램의 경우는 커널 레벨 쓰레드를 사용해야 한다.




'컴퓨터 공학과 졸업 > 운영체제' 카테고리의 다른 글

busy waiting  (0) 2018.08.10
메모리  (0) 2017.12.06
쓰레드  (0) 2017.10.14
Scheduling in Interactive Systems - 2  (0) 2017.10.13
Scheduling in Interactive Systems  (0) 2017.10.13
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함