해당 게시글은 kocw에서 제공하는 금오공과대학교 최태영 교수님의 무료 강의를 공부하고 정리하기 위해서 만들어졌습니다.
운영체제에서 사용하는 스레드 예제
- Windows Threads
- win 98 부터 일관된 스레드 함수를 제공했다.
- 기본적으로 one-to-one 매핑을 사용하며,
- kernel-level 스레드를 제공하고 있다.
- many-to-one, many-to-many 모델들은 thirdparty 라이브러리로 제공된다.
- 스레드는 스레드 아이디와 컨텍스트를 담고 있는 register set과 stack을 갖고 있는데, 두가지 스택을 가진다.
- user stack
- user가 function call을 부를 때마다 쌓인다.
- return address, parameter, local variable
- kernel stack
- user가 system.call을 호출하게 되면,
- 여전히 현재 프로세스는 유저 프로세스라고 판단하고
- 대신 모드만 커널 모드로 변경이 된다.
- 인터럽트 핸들러 루틴을 수행하면 중간에 함수를 호출하는데 이 때 쌓이는 스택을 커널 스택이라고 한다.
- 커널 내부에 존재하는 스택이다.
- 개인 주소, thread-local storage 같은 것들이 내부 구조로 관리된다.
- 이러한 구조를 제공하기 위해 세 가지의 자료 구조를 하나의 스레드를 위해 사용한다.
- 커널에서는 두 가지 구조체를 만든다.
- EThread
- 스레드가 시작되는 코드 주소
- EThread의 부모 스레드의 정보(TCB) 위치
- 이 것을 통해 부모 스레드의 전역 변수에 접근 가능하다.
- KThread
- 스케줄이나 동기화를 위한 정보
- 이 스레드가 cpu를 얼마나 사용했는지,
- 이 스레드가 어떤 함수를 통해 블락이 됐는지
- 커널 스택
- 이 두가지 모두 하나의 스레드를 관리하기 위해 생성된다.
- TEB
- 유저 스택이 내부에 존재한다.
- Thread-local storage(TLS)
- 따라서 한 스레드의 정보를 보려면 세 가지의 자료구조를 모두 접근해야 한다.
- 굳이 세 단계로 나눌 필요는 모르겠으나, 유저 단계에서 접근해야할 정보와 커널 단계에서 접근할 정보는 구분할 필요 있다.
- Linux Threads
- 원래 리눅스는 자체적으로 스레드 기능을 제공하지 않았다.
- 결국 나중에 스레드를 제공하기 위해서 변칙적인 방법을 사용했다.
- clone 방식
- 프로세스를 만들 때, clone이라는 방식을 사용하여 조금 다른 프로세스를 생성해 주는 시스템 콜을 제공한다.
- 이 클론을 생성할 때, 4가지 플래그를 설정한다.
- 부모 프로세스의 파일 시스템 공유 여부
- 부모 프로세스의 어드레스 스페이스 공유 여부
- 공유하게 되면 부모 전역 변수를 접근할 수 있다.
- 시그널 핸들러 공유 여부
- 각 프로세스는 별도의 시그널 핸들러를 가지는데,
- 스레드는 시그널 핸들러를 공유한다.
- 이 것을 공유함으로써 스레드와 동일하게 사용 가능해 지는 것이다.
- 오픈된 파일 공유 여부
- 클론은 성능 면에서 그렇게 좋지는 못하다.
- Pthread
- Pthread를 사용하지만 스레드 기능은 기본적으로 커널에서 제공해 주어야 하기 때문에,
- 결국 내부에서는 clone을 사용한다.