[운영체제] 4. Thread

임호연·2021년 5월 21일
0

기록

목록 보기
4/20
post-thumbnail

쓰레드

왜 생겼을까(프로세스보다 나은 점)

  • 프로세스 = 리소스 + 쓰레드(실행 흐름)

  • 프로세스를 생성하는 건 자원과 시간이 많이 든다.

    그런데, 이러한 프로세스를 만들어서 같은 자원으로 같은 일을 하게끔 시키면 비 효율적

    ex) 레지스터도 계속 바뀌어야 하고,, 데이터도 계속 바뀌어야 하고,,

  • heap을 쓰레드 마다 sub dividing 하긴 해요.

장점

  • 응답성

    gui 등등,,

  • 자원 공유 : 같은 주소 공간 내의 자원에서 다른 흐름

  • 경제성 : 프로세스의 자원을 공유함에 따름. 문맥 교환과 프로세스 생성에 효율적(메모리, 시간)

    유저레벨 쓰레드라면 확실히 문맥교환이 빠르다.

  • scalability : 다중 처리기에서,

다중 처리기 정의

  • 다중 처리기 이전에는, 병행성을 빠르게 해서 병렬성의 환상을 심어줌.

    다중 처리기는 실제로 병렬성을 보여준다.

  • 암달의 법칙

    순차 실행이 많다면, 코어를 많이 만들어도 성능 향상을 많이 얻을 수 없다

병렬 실행의 유형

  • 테스크 병렬실행

    웹 브라우저 처럼, 각각의 데이터를 적당히 쓰는 것

  • 데이터 병렬실행

    마치 딥러닝 처럼 쫙 나누는 느낌

어차피 둘 다 쓰게 된다.

쓰레드 컨텍스트 스위칭

현재 진행중인 쓰레드에 대한 레지스터와 TCB, stack등을 저장하고

레디큐에서 새로 진행할 쓰레드를 뺸 다음에

새로 진행할 쓰레드의 그런거를 processor에 적재한다.

쓰레드 진행 시 TCB POITNER를 이용해서 현재 TCB를 가리키게끔 행동하게 한다.

유저레벨에서의 premption은 upcall을 통해 구현 가능하다.

모델 유형

다대일모델(사용자모델)

  • user process의 라이브러리로 실행

    스케줄링, context switching, create, destory, thread끼리의 통신 등등 모두 다 지들이 알아서 할 수 밖에 없네,,

  • 빠르다

  • I/O 등에 의한 block시 전체가 block

    시스템 콜 할 때 리턴 값으로 어떤 thread한테 반환해야 하는 지도 잘 모른다.

  • 병렬 실행이 불가능하다.

    즉, 다중 코어 좆까라이다.

일대일 모델

  • 하나의 커널 쓰레드가 하나의 유저 쓰레드를 돌리는 방식
  • 커널 쓰레드가 cpu를 할당하는 기준이 된다.
  • 시스템 콜의 오버헤드가 크다.(문맥전환등)
  • 유저 쓰레드를 만들려면, 커널 쓰레드를 또 만들어야 한다.

다대다 모델

  • 하나의 커널 스레드를 가지고, 여러 개의 유저스레드가 나눠먹는 방식이다.
  • 상당량을 유저레벨에서 처리한다. 유저가 알아서 쓰레드 실행흐름일 때 자기 꺼에 붙인다.
  • userlevel scheduling과 kernel scheduling이 따로 존재하게 된다.

쓰레드 라이브러리

  • 유닉스 : 사용자, 커널 모두 가능한 쓰레드 라이브러리

    윈도우 : 커널 수준 라이브러리

  • 비동기 스레딩 : 안 기다리고 다른 일

    동기 스레딩 : 딱딱 타이밍 맞춰서.

리눅스 라이브러리1

  • 여담

    fork 하면, 다른 쓰레드 들은 모두 죽어버린다.

    exec하면, 아예 새로 써버리기 때문에 상관 없지만,

    그 전에는 메모리 누수 등의 심각한 문제들이 발생 가능,

    심지어, 다른 쓰레드에서 어떤 공유변수에 접근한 상태였다면, mutex lock같은 자원을 들고 죽어버리게 된다.

    상황에 따라 다를 수도 있다.

  • 윈도우도 그냥 비슷하구나..

여담 - jvm

  • jvm - 내부에서

  • 일단 두가지 스레드 방식

    1. runnable class

    2. executor class

암묵적 스레딩

운체와 컴파일러가 알아서 해쥬,,ㅚ

암묵적 스레딩 - 스레딩

  • 무한히 스레드를 만들 순 없으니, 양을 정하자

  • 장점

    적절한 양 제한

    애초에 스레드를 만들어 두는게 더 빠르다

  • 안드로이드 서비스는 일단 스레드 풀을 열어놓고 합니다.

    백그라운드에서 스레드풀을 열어 놓고, 배분해주는 방식

    서비스가 RPC로 이루어져 있다는 것은.. 알겠죠?

암묵적 스레딩 - fork join

  • 이전의 스레드 라이브러리 같은 느낌

    만들고, 이를 기다리기

  • 진짜 fork join을 말하는 것은 아닙니다.

OPEN MP

  • C, C++로 작성된 API,, 공유 메모리 환경의 병렬프로그래밍
  • 이와 비슷한 그런거 정말 참 귀찮아..

신호 처리

  • 디폴트 signal handler가 있구여, 프로그램마다 signal handler를 정할 수 있어요.

  • 쓰레드를 위한 kill이 있다.

    pthread_kill(pthread_t tid, int signal)

  • 윈도우는 비동기식 프로시저 호출을 한다. 그냥 어떤 이벤트에 어떤 함수를 실행할 건지 어플리케이션에서 해놓고, 커널에서 프로시저 호출을 함

쓰레드 취소

  • 만약, 어떤 쿼리를 막 100개의 스레드가 찾았는데, 하나가 찾았어, 그러면 다른 애들은 다 꺼야지

  • 문제점(어려운 점)

    취소 스레드에게 할당된 자원 문제

    작업 중 취소되는 문제

  • 지연취소는 물론 좀 덜함

    pthread_testcancel() : 자식 스레드가, 혹시 밖에서 취소요청 들어왔는지 확인하는 일.

    정리핸들러를 돌려서 thread가 얻어 놓은 자원을 다 뱉어놓는다.

스레드 로컬 저장장치

  • 자기 자신, 해당 쓰레드만 접근할 수 있는 영역
  • 쓰레드의 정적데이터라고 보면 될 듯

스케쥴러 액티베이션

  • 다대다의 해법

LWP

  • 사용자 스레드와 커널 스레드의 중간

  • LWP는 커널 스레드 하나를 받는다.

  • 스케줄링은 커널 스레드마다 실행된다.

    사용자 스레드 입장에서는, 마치 프로세서 처럼 보인다.

  • 가용한 커널 스레드 풀(LWPS)을 가지고, 유저 프로세스에게 upcall을 때린다.

    upcall 자체도 일단 커널스레드에서 실행한다.

    그러면, 유저 프로세스의 스레드 라이브러리의 upcall 프로시저를 커널 스레드에서 실행한다.

    이런 방식으로, 몇 개의 커널 스레드들을 주고 알아서 스케쥴링 하게끔 한다.

  • 블록이 된 상황에서, 커널 스레드가 결국 실행하므로 업콜을 때려서, 스레드 라이브러리에서 스케줄링을 하게 해준다. 스레드 라이브러리에서 스케줄링 하기 위해 새로운 LWP를 발행해준다. 그러면, 해당 스레드 라이브러리에서 막 콘택스트 스위칭 같은 거르 한다.

  • 블록이 풀리는 상황에는, 다시 커널에서 유저 스레드 라이브러리로 업콜을 때려주고, LWP 받아서 핸들러 실행하고, 새로운 LWP 받아가지고 실행하려는 스레드에 붙여주고,, 한다.

운영체제 별 스레드의 구조

윈도우

  • 커널 스케쥴링을 합니당.
  • 실행 스레드 블록 (ETHREAD)
  • 커널 스레드 블록 (KTHREAD)
  • TEB ( 유저 스페이스 내의 스레드 관련 정보 블록 )

리눅스

  • 클론 시스템 콜 fork 와 비슷함

  • 어느 정도 clone의 범위를 정할 수 있게 해준다.
profile
해탈하자

0개의 댓글