SlideShare a Scribd company logo
1 of 24
Ch06. 스레드의 기본
제프리 리처의 Windows via C/C++
김형주
스레드의 기본
1. 스레드를 생성해야 하는 경우
2. 스레드를 생성하지 말아야 하는 경우
3. 처음으로 작성하는 스레드 함수
4. CreateThread 함수
5. 스레드의 종료
6. 스레드의 내부
7. C/C++ 런타임 라이브러리에 대한 고찰
8. 자신의 구분자 얻기
• 스레드(thread)
• 프로세스 내에서 실행되는 흐름의 단위로, 실제로 작업을 수행하는 주체. 일반적으로 한 프로그램은 하나의 스
레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을
멀티스레드(multithread)라고 한다.
• 멀티프로세스와 멀티스레드
• 양쪽 모두 여러 흐름이 동시에 진행된다는 공통점.
• 하지만 멀티프로세스에서 각 프로세스는 독립적으로 실행되며 각각 별개의 메모리를 차지하고 있는 것과 달
리 멀티스레드는 프로세스 내의 메모리를 공유해 사용할 수 있다.
• 또한 프로세스 간의 전환 속도보다 스레드 간의 전환 속도가 빠르다.
• 멀티스레드의 다른 장점은 CPU가 여러 개일 경우에 각각의 CPU가 스레드 하나씩을 담당하는 방법으로 속도를
높일 수 있다는 것이다. 이러한 시스템에서는 여러 스레드가 실제 시간상으로 동시에 수행될 수 있기 때문이다.
• 멀티스레드의 단점에는 각각의 스레드 중 어떤 것이 먼저 실행될지 그 순서를 알 수 없다는 것이 있다.
스레드(thread)
출처: 위키백과, 스레드(컴퓨팅)
• 스레드의 구성
• 스레드 커널 오브젝트
• 운영체제가 스레드를 다루기 위한 커널 오브젝트. 시스템이 스레드에 대한 통계 정보를 저장하는 공간.
• 스레드 스택
• 코드를 수행할 때 함수의 매개변수와 지역변수를 저장하기 위한 스레드 스택
• 스레드와 프로세스
• 스레드는 항상 프로세스의 컨텍스트 내에 생성되며, 프로세스 안에만 살아 있을 수 있다.
• 프로세스 내에 둘 이상의 스레드가 존재하는 경우, 스레드들은 단일 주소 공간을 공유.
• 프로세스의 커널 오브젝트 핸들 테이블 또한 공유하게 된다.
스레드와 프로세스
스레드와 프로세스
1. 스레드를 생성해야 하는 경우
프로세스
초기화
주 스레드
생성
시작 코드 수행
(C/C++ 런타임
라이브러리 )
진입점 함수
(_tmain) 호
출
진입점 함수
반환
시작 코드의
ExitProcess
호출
수행 종료
스레드: 프로세스 내의 수행 흐름
1. 스레드를 생성해야 하는 경우
• 계속해서 CPU가 작업을 수행하도록 할 때(유휴 상태가 되지 않게)
• 윈도우 운영체제의 인덱스 서비스(Index Service)
• 디스크 드라이브에 있는 파일에 대해 인덱싱을 수행.
• 검색 속도 향상
• 운영체제의 디스크 조각 모음 백그라운드로 수행
• Visual Strudio IDE 는 C# 등 코드 자동으로 컴파일
• 웹 브라우저는 백그라운드로 서버와 통신을 수행
• 웹 사이트 전부 로드되기 전 작업 수행 가능
• 멀티 스레딩
• 사용자 인터페이스를 단순화
• 자동 컴파일, 문법 검사 등
• I/O를 분리된 스레드로 수행해 사용자 인터페이스 응답성 향상
2. 스레드를 생성하지 말아야 하는 경우
• 한 스레드가 다른 스레드의 자료를 잘못 변경하는 경우
• 예) 프린트 작업 중 문서 수정
• 높은 우선 순위의 단일 사용자 인터페이스 스레드를 이용해 응답성 개선
• 반면, 윈도우 탐색기는 각각의 폴더 윈도우를 다른 스레드로 생성하여 응답성 개선
• 다수의 스레드로 사용자 인터페이스를 구성하는 방식은 신중하게 사용해야
3. 처음으로 작성하는 스레드 함수
• 모든 스레드는 진입점 함수를 반드시 가진다.
• 주 스레드의 진입점 함수 이름은 main, wmain, WinMain, 또는 wWinMain이어
야 하지만, 스레드 함수는 어떠한 이름이라도 사용될 수 있다.
• 애플리케이션에 여러 개의 스레드 함수가 필요하다면 각각은 서로 다른 이름
으로 명명되어야만 한다.
3. 처음으로 작성하는 스레드 함수
• 스레드 함수는 반드시 값을 반환 한다. 이 값은 스레드의 종료 코드가 된다.
• 스레드 함수는 가능한 한 함수로 전달된 매개변수와 지역 local 변수만을 사용
하도록 작성
• 정적 변수나 전역 변수를 사용하게 되면 다수의 스레드 가동시 에 변수에 접근할 수 있게
되며 이는 변수의 값이 잘못 변경되는 원인이 되기도 한다.
4. CreateThread 함수
• 주 스레드가 아닌 두 번째 스레드 생성시 CreateThread 호출
• 시스템은 스레드 커널 오브젝트를 생성 및 스레드가 사용할 스택을 확보
• 새로운 스레드는 스레드를 생성한 프로세스와 동일한 컨텍스트에서 수행
• 프로세스의 커널 오브젝트 핸들 및 메모리, 다른 스레드의 스택에 접근이 가능
• 동일 프로세스 내의 스레드들은 손쉽게 상호 통신 가능
CreateThread 함수의 각 매개변수
• PSECURITY ATTRIBUTES psa
• SECURITY ATTRIBUTES 구조체 포인터. NULL 전달하면 기본 보안 특성 사용
• DWORD cbStackSize
• 스레드 스택에 얼마만큼의 공간을 사용할지를 지정
• 매개변수로 0을 전달하면 실행 파일 내에 포함된 커밋된 물리적 저장소의 초기 크기를 따름
• pfnStartAddr과 pvParam
• pfnStartAddr: 새로이 생성되는 스레드가 호출할 스레드 함수의 주소
• pvParam: 위 쓰레드 함수의 매개변수로 그대로 전달
• 윈도우는 선점형 멀티스레딩 시스템: 기존 스레드와 새로운 스레드 동시 수행 가능
• 이미 반환되어 스택이 파괴된 스레드에 다른 스레드가 접근할 가능성 주의
CreateThread 함수의 각 매개변수
• dwCreateFlags
• 스레드를 생성할 때 세부적인 제어를 수행하기 위한 추가적인 플래그 지정
• CREATE SUSPENDED를 전달하면 CPU에 바로 스케줄되지 않고 일시 정지 상태를 유지
• pdwThreadlD
• 새로운 스레드에 할당되는 스레드 ID 값을 저장할 DWORD 변수를 가리키는 주소
5. 스레드의 종료
• 스레드는 4가지 방법으로 종료
• 스레드 함수가 반환(추천)
• 스레드 함수 내에서 ExitThread 함수를 호출
• 동일한 프로세스나 다른 프로세스에서 TerminateThread 함수를 호출
• 스레드가 포함된 프로세스가 종료
스레드 함수 반환
• 스레드 함수 내에서 생성한 c++ 오브젝트들은 파괴자를 통해 적절히 제거
• 운영체제는 스레드 스택으로 사용하였던 메모리를 반환
• 시스템은 스레드의 종료 코드를 스레드 함수의 반환 값으로 설정
• 스레드 커널 오브젝트 내에 저장
• 시스템은 스레드 커널 오브젝트의 사용 카운트를 감소
스레드의 종료
• ExitThread 함수
• 스레드를 강제로 종료하고 운영체제가 스레드에서 사용했던 운영체제 리소스를 정리
• 하지만 c/c++ 리소스(c++ 클래스 오브젝트와 같은)는 정리되지 않는다.
• ExitThread 함수의 dwExitCode 매개변수를 이용하여 스레드의 종료 코드를 설정 가능
스레드의 종료
• TerminateThread 함수
• hThread 매개변수는 종료할 스레드의 핸들을 전달해 어떠한 스레드라도 종료 가능
• 스레드의 종료 코드는 dwExitCode 매개변수로 전달한 값으로 설정
• 스레드 커널 오브젝트의 사용 카운트는 감소
• 이 함수를 호출하면 종료될 스레드는 자신이 종료될 것이라는 사실을 전달받지 못하기
때문에 적절한 정리 작업을 수행할 수도 없고, 종료를 회피할 수 있는 방법도 없다.
스레드의 종료
• 프로세스가 종료
• ExitProcess와 TerminateProcess 함수를 호출하는 경우에도 스레드는 종료
• 프로세스가소유하고 있던 모든 스레드가 종료
• 프로세스가 사용하던 리소스 및 스레드들이 사용하던 스택들도 정리
• 프로세스 내에 남아 있는 스레드들에 대해 각각 TerminateThread 함수 호출
• 물론 C++ 파괴자가 호출되지도 못하고, 적절한 정리 작업도 수행되지 못한다.
스레드가 종료되면
• 스레드 소유의 모든 유저 오브젝트 핸들이 삭제
• 윈도우와 윈도우 혹 두 개의 사용자 오브젝트는 스레드에 의해 소유
• 스레드가 종료되면 시스템은 해당 스레드가 생성한 윈도우를 파괴하고 설치한 윈도우
혹을 제거
• 스레드의 종료 코드는 STILL_ACTIVE 에서 ExitThread나 TerminateThread에서 지정한
종료 코드로 변경
• 스레드 커널 오브젝트의 상태가 시그널 상태로 변경
• 종료되는 스레드가 프로세스의 마지막 스레드라면 시스템은 프로세스도 같이 종료
• 스레드 커널 오브젝트의 사용 카운트가 1 만큼 감소
6. 스레드의 내부
• CreateThread 함수가 호출되면 시스템은 스레드 커널 오브젝트를 생성한다.
• 이 오브젝트는 초기 사용 카운트 2
• 스레드 커널 오브젝트의 다른 속성들도 초기화
• 정지 카운트는 1, 종료 코드는 STILL ACTIVE(Ox103), 오브젝트의 상태는 non-signal로 각각 초기화
• 시스템은 스레드 스택으로 활용할 메모리 공간을 할당
• 스레드 스택으로 활용할 메모리는 프로세스의 주소 공간으로부터 할당
• 스택의 첫 번째 값은 pvParam 매개변수
• 두 번째 값은 pfnStartAddr 매개변수의 값이다.
6. 스레드의 내부
• 스레드의 초기화가 완료되고 CREATE SUSPENDED 플래그가 전달되지 않았으면, 시스템은 스레드의 정
지 카운트를 0으로 감소시켜 스레드가 프로세서에 스케줄
• 스레드가 CPU 시간을 얻으면 시스템은 스레드 컨텍스트에 마지막으로 저장된 값을 CPU 레지스터로 로
드한다. 그러면 스레드는 프로세스 주소 공간 내에 있는 코드를 수행
• 새로운 스레드의 인스트럭션 포인터가 RtlUserThreadStart로 설정, 이 함수는 스레드가 실질적으로 수
행하는 최초 위치
6. 스레드의 내부
• RtlUserThreadStart 함수는 C/C++ 런타임 라이브러리의 시작 코드를 호출하여 각종 초기화를 진행
• _tmain이나 tWinmain과 같은 진입점 함수를 호출
• 진입점 함수가 반환되면 C/C++ 런타임 라이브러리 시작 코드는 ExitProcess를 호출
• 따라서 C/C++ 애플리케이션의 주 스레드는 RtlUserThreadStart 함수로 절대 반환되지 않는다.
7. C/C++ 런타임 라이브러리에 대한 고찰
• 멀티스레드 기반의 C/C++ 프로그램이 정상적으로 동작하려면 C/C++ 런타임 라이브러리 함수들을 사
용하는 각 스레드별로 적절한 구조의 데이터 블록을 생성해야 한다.
• 또한 C/C++ 런타임 라이브러리 함수는 다른 스레드들로부터 영향을 받지 않도록 자신을 호출한 스레
드의 데이터 블록에만 접근 가능해야 한다.
• 새로운 스레드를 생성할 때는 운영체제가 제공하는 CreateThread 함수를 절대로 호출하지 말고 대신
C/C++ 런타임 라이브러리가 제공하고 있는 _beginthreadex 함수를 호출해야만 한다.
_beginthreadex 함수 특징
• 각 스레드는 C/C+ 런타임 라이브러리 협에 tiddata 메모리 블록을 가진다 .
• _beginthreadex 함수에 전달된 스레드 함수의 주소는 tiddata 메모리 블록 내에 저장된다.
• 스레드 함수에 전달할 매개변수 또한 tiddata 메모리 블록에 저장된다 .
• _beginthreadex는 내부적으로 CreateThread를 호출한다. 이것은 운영체제에게 새로운 스레드를 생성하
도록 명령하는 유일한 방법이다 .
• CreateThread가 호출되면 _beginthreadex의 pfnStartAddr 매개변수로 전달한 스레드 함수가 아니라
threadstartex라는 함수가 수행
• 또한 스레드 함수의 매개변수도 _beginthreadex에 전달한 pvparam이 아니라 tiddata 구조체의 주소
• 정상적인 경우 _beginthreadex는 CreateThread와 동일하게 스레드 핸들을 반환한다. 만일 문제가 발생
하면 0을 반환한다.

More Related Content

What's hot

07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도ssuser3fb17c
 
스레드
스레드스레드
스레드xxbdxx
 
Jupyter notebok tensorboard 실행하기_20160706
Jupyter notebok tensorboard 실행하기_20160706Jupyter notebok tensorboard 실행하기_20160706
Jupyter notebok tensorboard 실행하기_20160706Yong Joon Moon
 
Windows via c/c++ 스터디9장
Windows via c/c++ 스터디9장Windows via c/c++ 스터디9장
Windows via c/c++ 스터디9장HolyTak
 
비동기 파일 로딩
비동기 파일 로딩비동기 파일 로딩
비동기 파일 로딩Bongseok Cho
 
20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은
20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은
20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은jieun kim
 
Direct x 12 초기화
Direct x 12 초기화Direct x 12 초기화
Direct x 12 초기화QooJuice
 
[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기Daehee Kim
 
[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http Request
[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http Request[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http Request
[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http RequestNAVER D2
 
Apache ZooKeeper 소개
Apache ZooKeeper 소개Apache ZooKeeper 소개
Apache ZooKeeper 소개중선 곽
 
리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션QooJuice
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSCirculus
 
[143] Modern C++ 무조건 써야 해?
[143] Modern C++ 무조건 써야 해?[143] Modern C++ 무조건 써야 해?
[143] Modern C++ 무조건 써야 해?NAVER D2
 
Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object poolingNam Hyeonuk
 
20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은
20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은
20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은jieun kim
 
스톰 미리보기
스톰 미리보기스톰 미리보기
스톰 미리보기June Yi
 

What's hot (20)

07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도07 스레드스케줄링,우선순위,그리고선호도
07 스레드스케줄링,우선순위,그리고선호도
 
스레드
스레드스레드
스레드
 
Jupyter notebok tensorboard 실행하기_20160706
Jupyter notebok tensorboard 실행하기_20160706Jupyter notebok tensorboard 실행하기_20160706
Jupyter notebok tensorboard 실행하기_20160706
 
Lock free queue
Lock free queueLock free queue
Lock free queue
 
Gcd ppt
Gcd pptGcd ppt
Gcd ppt
 
04 프로세스
04 프로세스04 프로세스
04 프로세스
 
Windows via c/c++ 스터디9장
Windows via c/c++ 스터디9장Windows via c/c++ 스터디9장
Windows via c/c++ 스터디9장
 
비동기 파일 로딩
비동기 파일 로딩비동기 파일 로딩
비동기 파일 로딩
 
20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은
20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은
20150509 unix v6로 배우는 커널의 원리와 구조 3 김지은
 
Direct x 12 초기화
Direct x 12 초기화Direct x 12 초기화
Direct x 12 초기화
 
[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기[NDC 2016] 유니티, iOS에서 LINQ 사용하기
[NDC 2016] 유니티, iOS에서 LINQ 사용하기
 
[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http Request
[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http Request[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http Request
[D2 CAMPUS] 안드로이드 오픈소스 스터디자료 - Http Request
 
Apache ZooKeeper 소개
Apache ZooKeeper 소개Apache ZooKeeper 소개
Apache ZooKeeper 소개
 
리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션리플렉션과 가비지 컬렉션
리플렉션과 가비지 컬렉션
 
Startup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JSStartup JavaScript 8 - NPM, Express.JS
Startup JavaScript 8 - NPM, Express.JS
 
[143] Modern C++ 무조건 써야 해?
[143] Modern C++ 무조건 써야 해?[143] Modern C++ 무조건 써야 해?
[143] Modern C++ 무조건 써야 해?
 
Storm 훑어보기
Storm 훑어보기Storm 훑어보기
Storm 훑어보기
 
Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object pooling
 
20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은
20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은
20150502 unix v6로 배우는 커널의 원리와 구조 1 김지은
 
스톰 미리보기
스톰 미리보기스톰 미리보기
스톰 미리보기
 

Similar to Windows via C/C++ 06 스레드의 기본

뇌자T etc.windows multi threading programming
뇌자T   etc.windows multi threading programming뇌자T   etc.windows multi threading programming
뇌자T etc.windows multi threading programmingcancan21st
 
Windows via c++ chapter6
Windows via c++   chapter6Windows via c++   chapter6
Windows via c++ chapter6Shin heemin
 
쓰레드.pdf
쓰레드.pdf쓰레드.pdf
쓰레드.pdfSeokju Hong
 
파이썬 병렬프로그래밍
파이썬 병렬프로그래밍파이썬 병렬프로그래밍
파이썬 병렬프로그래밍Yong Joon Moon
 
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018devCAT Studio, NEXON
 
운영 체제 Sig
운영 체제 Sig운영 체제 Sig
운영 체제 SigYoungGun Na
 
운영체제 Sig4
운영체제 Sig4운영체제 Sig4
운영체제 Sig4Jiwan Yoon
 
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdfOS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdfHo Jeong Im
 
Linux programming study
Linux programming studyLinux programming study
Linux programming studyYunseok Lee
 
윈도우 커널 익스플로잇
윈도우 커널 익스플로잇윈도우 커널 익스플로잇
윈도우 커널 익스플로잇Seungyong Lee
 
Backend Master | 3.4.5 Deploy - Docker Principal
Backend Master | 3.4.5 Deploy - Docker PrincipalBackend Master | 3.4.5 Deploy - Docker Principal
Backend Master | 3.4.5 Deploy - Docker PrincipalKyunghun Jeon
 
테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템QooJuice
 
CUDA 프로그래밍 기초 MODUCON2018
CUDA 프로그래밍 기초 MODUCON2018CUDA 프로그래밍 기초 MODUCON2018
CUDA 프로그래밍 기초 MODUCON2018Shengzhe Li
 
[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTO
[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTO[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTO
[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTOiFunFactory Inc.
 
오픈소스 소프트웨어 성능 최적화 보고서 2장.
오픈소스 소프트웨어 성능 최적화 보고서 2장.오픈소스 소프트웨어 성능 최적화 보고서 2장.
오픈소스 소프트웨어 성능 최적화 보고서 2장.HyeonSeok Choi
 

Similar to Windows via C/C++ 06 스레드의 기본 (20)

뇌자T etc.windows multi threading programming
뇌자T   etc.windows multi threading programming뇌자T   etc.windows multi threading programming
뇌자T etc.windows multi threading programming
 
Windows via c++ chapter6
Windows via c++   chapter6Windows via c++   chapter6
Windows via c++ chapter6
 
쓰레드.pdf
쓰레드.pdf쓰레드.pdf
쓰레드.pdf
 
파이썬 병렬프로그래밍
파이썬 병렬프로그래밍파이썬 병렬프로그래밍
파이썬 병렬프로그래밍
 
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018
이승재, 실버바인 서버엔진 2 설계 리뷰, NDC2018
 
운영 체제 Sig
운영 체제 Sig운영 체제 Sig
운영 체제 Sig
 
운영체제 Sig4
운영체제 Sig4운영체제 Sig4
운영체제 Sig4
 
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdfOS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
OS Process, Thread, CPU Scheduling에 대해 알아봅시다.pdf
 
System+os study 3
System+os study 3System+os study 3
System+os study 3
 
Linux programming study
Linux programming studyLinux programming study
Linux programming study
 
Warp
WarpWarp
Warp
 
윈도우 커널 익스플로잇
윈도우 커널 익스플로잇윈도우 커널 익스플로잇
윈도우 커널 익스플로잇
 
Backend Master | 3.4.5 Deploy - Docker Principal
Backend Master | 3.4.5 Deploy - Docker PrincipalBackend Master | 3.4.5 Deploy - Docker Principal
Backend Master | 3.4.5 Deploy - Docker Principal
 
Kubernetes
Kubernetes Kubernetes
Kubernetes
 
테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템
 
CUDA 프로그래밍 기초 MODUCON2018
CUDA 프로그래밍 기초 MODUCON2018CUDA 프로그래밍 기초 MODUCON2018
CUDA 프로그래밍 기초 MODUCON2018
 
Network researching
Network researchingNetwork researching
Network researching
 
[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTO
[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTO[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTO
[MGDC] 리눅스 게임 서버 성능 분석하기 - 아이펀팩토리 김진욱 CTO
 
Node.js 기본
Node.js 기본Node.js 기본
Node.js 기본
 
오픈소스 소프트웨어 성능 최적화 보고서 2장.
오픈소스 소프트웨어 성능 최적화 보고서 2장.오픈소스 소프트웨어 성능 최적화 보고서 2장.
오픈소스 소프트웨어 성능 최적화 보고서 2장.
 

Windows via C/C++ 06 스레드의 기본

  • 1. Ch06. 스레드의 기본 제프리 리처의 Windows via C/C++ 김형주
  • 2. 스레드의 기본 1. 스레드를 생성해야 하는 경우 2. 스레드를 생성하지 말아야 하는 경우 3. 처음으로 작성하는 스레드 함수 4. CreateThread 함수 5. 스레드의 종료 6. 스레드의 내부 7. C/C++ 런타임 라이브러리에 대한 고찰 8. 자신의 구분자 얻기
  • 3. • 스레드(thread) • 프로세스 내에서 실행되는 흐름의 단위로, 실제로 작업을 수행하는 주체. 일반적으로 한 프로그램은 하나의 스 레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티스레드(multithread)라고 한다. • 멀티프로세스와 멀티스레드 • 양쪽 모두 여러 흐름이 동시에 진행된다는 공통점. • 하지만 멀티프로세스에서 각 프로세스는 독립적으로 실행되며 각각 별개의 메모리를 차지하고 있는 것과 달 리 멀티스레드는 프로세스 내의 메모리를 공유해 사용할 수 있다. • 또한 프로세스 간의 전환 속도보다 스레드 간의 전환 속도가 빠르다. • 멀티스레드의 다른 장점은 CPU가 여러 개일 경우에 각각의 CPU가 스레드 하나씩을 담당하는 방법으로 속도를 높일 수 있다는 것이다. 이러한 시스템에서는 여러 스레드가 실제 시간상으로 동시에 수행될 수 있기 때문이다. • 멀티스레드의 단점에는 각각의 스레드 중 어떤 것이 먼저 실행될지 그 순서를 알 수 없다는 것이 있다. 스레드(thread) 출처: 위키백과, 스레드(컴퓨팅)
  • 4. • 스레드의 구성 • 스레드 커널 오브젝트 • 운영체제가 스레드를 다루기 위한 커널 오브젝트. 시스템이 스레드에 대한 통계 정보를 저장하는 공간. • 스레드 스택 • 코드를 수행할 때 함수의 매개변수와 지역변수를 저장하기 위한 스레드 스택 • 스레드와 프로세스 • 스레드는 항상 프로세스의 컨텍스트 내에 생성되며, 프로세스 안에만 살아 있을 수 있다. • 프로세스 내에 둘 이상의 스레드가 존재하는 경우, 스레드들은 단일 주소 공간을 공유. • 프로세스의 커널 오브젝트 핸들 테이블 또한 공유하게 된다. 스레드와 프로세스
  • 6. 1. 스레드를 생성해야 하는 경우 프로세스 초기화 주 스레드 생성 시작 코드 수행 (C/C++ 런타임 라이브러리 ) 진입점 함수 (_tmain) 호 출 진입점 함수 반환 시작 코드의 ExitProcess 호출 수행 종료 스레드: 프로세스 내의 수행 흐름
  • 7. 1. 스레드를 생성해야 하는 경우 • 계속해서 CPU가 작업을 수행하도록 할 때(유휴 상태가 되지 않게) • 윈도우 운영체제의 인덱스 서비스(Index Service) • 디스크 드라이브에 있는 파일에 대해 인덱싱을 수행. • 검색 속도 향상 • 운영체제의 디스크 조각 모음 백그라운드로 수행 • Visual Strudio IDE 는 C# 등 코드 자동으로 컴파일 • 웹 브라우저는 백그라운드로 서버와 통신을 수행 • 웹 사이트 전부 로드되기 전 작업 수행 가능 • 멀티 스레딩 • 사용자 인터페이스를 단순화 • 자동 컴파일, 문법 검사 등 • I/O를 분리된 스레드로 수행해 사용자 인터페이스 응답성 향상
  • 8. 2. 스레드를 생성하지 말아야 하는 경우 • 한 스레드가 다른 스레드의 자료를 잘못 변경하는 경우 • 예) 프린트 작업 중 문서 수정 • 높은 우선 순위의 단일 사용자 인터페이스 스레드를 이용해 응답성 개선 • 반면, 윈도우 탐색기는 각각의 폴더 윈도우를 다른 스레드로 생성하여 응답성 개선 • 다수의 스레드로 사용자 인터페이스를 구성하는 방식은 신중하게 사용해야
  • 9. 3. 처음으로 작성하는 스레드 함수 • 모든 스레드는 진입점 함수를 반드시 가진다. • 주 스레드의 진입점 함수 이름은 main, wmain, WinMain, 또는 wWinMain이어 야 하지만, 스레드 함수는 어떠한 이름이라도 사용될 수 있다. • 애플리케이션에 여러 개의 스레드 함수가 필요하다면 각각은 서로 다른 이름 으로 명명되어야만 한다.
  • 10. 3. 처음으로 작성하는 스레드 함수 • 스레드 함수는 반드시 값을 반환 한다. 이 값은 스레드의 종료 코드가 된다. • 스레드 함수는 가능한 한 함수로 전달된 매개변수와 지역 local 변수만을 사용 하도록 작성 • 정적 변수나 전역 변수를 사용하게 되면 다수의 스레드 가동시 에 변수에 접근할 수 있게 되며 이는 변수의 값이 잘못 변경되는 원인이 되기도 한다.
  • 11. 4. CreateThread 함수 • 주 스레드가 아닌 두 번째 스레드 생성시 CreateThread 호출 • 시스템은 스레드 커널 오브젝트를 생성 및 스레드가 사용할 스택을 확보 • 새로운 스레드는 스레드를 생성한 프로세스와 동일한 컨텍스트에서 수행 • 프로세스의 커널 오브젝트 핸들 및 메모리, 다른 스레드의 스택에 접근이 가능 • 동일 프로세스 내의 스레드들은 손쉽게 상호 통신 가능
  • 12. CreateThread 함수의 각 매개변수 • PSECURITY ATTRIBUTES psa • SECURITY ATTRIBUTES 구조체 포인터. NULL 전달하면 기본 보안 특성 사용 • DWORD cbStackSize • 스레드 스택에 얼마만큼의 공간을 사용할지를 지정 • 매개변수로 0을 전달하면 실행 파일 내에 포함된 커밋된 물리적 저장소의 초기 크기를 따름 • pfnStartAddr과 pvParam • pfnStartAddr: 새로이 생성되는 스레드가 호출할 스레드 함수의 주소 • pvParam: 위 쓰레드 함수의 매개변수로 그대로 전달 • 윈도우는 선점형 멀티스레딩 시스템: 기존 스레드와 새로운 스레드 동시 수행 가능 • 이미 반환되어 스택이 파괴된 스레드에 다른 스레드가 접근할 가능성 주의
  • 13. CreateThread 함수의 각 매개변수 • dwCreateFlags • 스레드를 생성할 때 세부적인 제어를 수행하기 위한 추가적인 플래그 지정 • CREATE SUSPENDED를 전달하면 CPU에 바로 스케줄되지 않고 일시 정지 상태를 유지 • pdwThreadlD • 새로운 스레드에 할당되는 스레드 ID 값을 저장할 DWORD 변수를 가리키는 주소
  • 14. 5. 스레드의 종료 • 스레드는 4가지 방법으로 종료 • 스레드 함수가 반환(추천) • 스레드 함수 내에서 ExitThread 함수를 호출 • 동일한 프로세스나 다른 프로세스에서 TerminateThread 함수를 호출 • 스레드가 포함된 프로세스가 종료
  • 15. 스레드 함수 반환 • 스레드 함수 내에서 생성한 c++ 오브젝트들은 파괴자를 통해 적절히 제거 • 운영체제는 스레드 스택으로 사용하였던 메모리를 반환 • 시스템은 스레드의 종료 코드를 스레드 함수의 반환 값으로 설정 • 스레드 커널 오브젝트 내에 저장 • 시스템은 스레드 커널 오브젝트의 사용 카운트를 감소
  • 16. 스레드의 종료 • ExitThread 함수 • 스레드를 강제로 종료하고 운영체제가 스레드에서 사용했던 운영체제 리소스를 정리 • 하지만 c/c++ 리소스(c++ 클래스 오브젝트와 같은)는 정리되지 않는다. • ExitThread 함수의 dwExitCode 매개변수를 이용하여 스레드의 종료 코드를 설정 가능
  • 17. 스레드의 종료 • TerminateThread 함수 • hThread 매개변수는 종료할 스레드의 핸들을 전달해 어떠한 스레드라도 종료 가능 • 스레드의 종료 코드는 dwExitCode 매개변수로 전달한 값으로 설정 • 스레드 커널 오브젝트의 사용 카운트는 감소 • 이 함수를 호출하면 종료될 스레드는 자신이 종료될 것이라는 사실을 전달받지 못하기 때문에 적절한 정리 작업을 수행할 수도 없고, 종료를 회피할 수 있는 방법도 없다.
  • 18. 스레드의 종료 • 프로세스가 종료 • ExitProcess와 TerminateProcess 함수를 호출하는 경우에도 스레드는 종료 • 프로세스가소유하고 있던 모든 스레드가 종료 • 프로세스가 사용하던 리소스 및 스레드들이 사용하던 스택들도 정리 • 프로세스 내에 남아 있는 스레드들에 대해 각각 TerminateThread 함수 호출 • 물론 C++ 파괴자가 호출되지도 못하고, 적절한 정리 작업도 수행되지 못한다.
  • 19. 스레드가 종료되면 • 스레드 소유의 모든 유저 오브젝트 핸들이 삭제 • 윈도우와 윈도우 혹 두 개의 사용자 오브젝트는 스레드에 의해 소유 • 스레드가 종료되면 시스템은 해당 스레드가 생성한 윈도우를 파괴하고 설치한 윈도우 혹을 제거 • 스레드의 종료 코드는 STILL_ACTIVE 에서 ExitThread나 TerminateThread에서 지정한 종료 코드로 변경 • 스레드 커널 오브젝트의 상태가 시그널 상태로 변경 • 종료되는 스레드가 프로세스의 마지막 스레드라면 시스템은 프로세스도 같이 종료 • 스레드 커널 오브젝트의 사용 카운트가 1 만큼 감소
  • 20. 6. 스레드의 내부 • CreateThread 함수가 호출되면 시스템은 스레드 커널 오브젝트를 생성한다. • 이 오브젝트는 초기 사용 카운트 2 • 스레드 커널 오브젝트의 다른 속성들도 초기화 • 정지 카운트는 1, 종료 코드는 STILL ACTIVE(Ox103), 오브젝트의 상태는 non-signal로 각각 초기화 • 시스템은 스레드 스택으로 활용할 메모리 공간을 할당 • 스레드 스택으로 활용할 메모리는 프로세스의 주소 공간으로부터 할당 • 스택의 첫 번째 값은 pvParam 매개변수 • 두 번째 값은 pfnStartAddr 매개변수의 값이다.
  • 21. 6. 스레드의 내부 • 스레드의 초기화가 완료되고 CREATE SUSPENDED 플래그가 전달되지 않았으면, 시스템은 스레드의 정 지 카운트를 0으로 감소시켜 스레드가 프로세서에 스케줄 • 스레드가 CPU 시간을 얻으면 시스템은 스레드 컨텍스트에 마지막으로 저장된 값을 CPU 레지스터로 로 드한다. 그러면 스레드는 프로세스 주소 공간 내에 있는 코드를 수행 • 새로운 스레드의 인스트럭션 포인터가 RtlUserThreadStart로 설정, 이 함수는 스레드가 실질적으로 수 행하는 최초 위치
  • 22. 6. 스레드의 내부 • RtlUserThreadStart 함수는 C/C++ 런타임 라이브러리의 시작 코드를 호출하여 각종 초기화를 진행 • _tmain이나 tWinmain과 같은 진입점 함수를 호출 • 진입점 함수가 반환되면 C/C++ 런타임 라이브러리 시작 코드는 ExitProcess를 호출 • 따라서 C/C++ 애플리케이션의 주 스레드는 RtlUserThreadStart 함수로 절대 반환되지 않는다.
  • 23. 7. C/C++ 런타임 라이브러리에 대한 고찰 • 멀티스레드 기반의 C/C++ 프로그램이 정상적으로 동작하려면 C/C++ 런타임 라이브러리 함수들을 사 용하는 각 스레드별로 적절한 구조의 데이터 블록을 생성해야 한다. • 또한 C/C++ 런타임 라이브러리 함수는 다른 스레드들로부터 영향을 받지 않도록 자신을 호출한 스레 드의 데이터 블록에만 접근 가능해야 한다. • 새로운 스레드를 생성할 때는 운영체제가 제공하는 CreateThread 함수를 절대로 호출하지 말고 대신 C/C++ 런타임 라이브러리가 제공하고 있는 _beginthreadex 함수를 호출해야만 한다.
  • 24. _beginthreadex 함수 특징 • 각 스레드는 C/C+ 런타임 라이브러리 협에 tiddata 메모리 블록을 가진다 . • _beginthreadex 함수에 전달된 스레드 함수의 주소는 tiddata 메모리 블록 내에 저장된다. • 스레드 함수에 전달할 매개변수 또한 tiddata 메모리 블록에 저장된다 . • _beginthreadex는 내부적으로 CreateThread를 호출한다. 이것은 운영체제에게 새로운 스레드를 생성하 도록 명령하는 유일한 방법이다 . • CreateThread가 호출되면 _beginthreadex의 pfnStartAddr 매개변수로 전달한 스레드 함수가 아니라 threadstartex라는 함수가 수행 • 또한 스레드 함수의 매개변수도 _beginthreadex에 전달한 pvparam이 아니라 tiddata 구조체의 주소 • 정상적인 경우 _beginthreadex는 CreateThread와 동일하게 스레드 핸들을 반환한다. 만일 문제가 발생 하면 0을 반환한다.