스레드가 가지고 있는 정보들
- CPU레지스터 정보(=컨텍스트)
- 현재 모드
- 스택
- 개인 저장 영역
- 임의의 보안 토큰
- 메시지 큐
- 메시지 큐를 이용해 윈도우나 스레드를 생성하고 관리할 수 잇다.
- 스레드 우선순위
- 스레드 상태 정보
스레드 관련 API
- 스레드 생성
- CreateThread
- 스레드 일시중지 / 재개
- SuspendThread
- ResumeThread
- 스레드 종료
- ExitThread
- Terminate Thread
1.스레드 스택
스레드는 2개의 스택을 가지고 있다.
- 커널모드에서 사용하는 물리메모리 스택
- 32비트에서는 12kb, 64비트에서는 24kb
- 유저모드에서 사용하는 스택
- 기본 1mb로 예약되고 공간이 더필요할 때 4kb씩 증가되어 커밋되며, 기본크기는 64kb로 생김
- linker를 이용하여 기본 크기 지정 가능
- CreateThread함수나 CreateRemoteThread함수를 이용하여 크기 조절 가능
2. 스레드 우선순위
- 우선순위 레벨은 0~31까지 존재
- 우선순위 숫자가 높을 수록 빠른 처리가 필요한 스레드이다.
- 가장 낮은 우선순위인 0번은 ZeroPage Thread라는 프로세스가 사용하여 프로세스에서 더이상 사용하지 않는 메모리를 해제해준다.
- 자신이 속한 프로세스 우선순위에 따라 스레드 우선순위가 결정되며 내부에서도 우선순위가 결정된다
- 물론 API로 우선순위를 변경할 수 있다. (SetThreadPriority)
- 시스템 권한이 충분하지 않은 경우 우선순위는 15이상을 넘어갈 수 없다.
3. 클럭과 퀀텀
- 프로세서를 사용할 대는 Clacks을 기준으로 삼는데 만약 한번 처리하고 다른 스레드로 변경하게 된다면 Context Switching을 진행해야한다
- Context Switching : 스레드가 이전에 사용하던 프로세서에서 처리완료하지 못하고 다른 스레드로 변경되어야 할 때, 처리를 재개하기 위해 프로세서에서 처리하던 정보를 저장해둔 데이터
- 매 클럭마다 컨텍스트 스위칭을 진행하게 된다면 cpu는 스레드에서 처리하는 작업보다 스레드 변경을 위해 컨텍스트를 저장하는 작업이 더 많아질 것이다. 그래서 Quantum을 이용하여 클럭을 알맞은 횟수만큼 하나의 스레드가 사용할 수 있도록 한다
- 퀀텀 1 = 클럭 1 : 퀀텀이 1이라면 1 클럭동안 실행이 가능하며 , 자신의 퀀텀 값이 0이되면 컨텍스트 스위칭이 일어난다.
- OS마다 기본적인 쿼넘 값이 다르게 설정되어 있다.
- 퀀텀 값은 레지스트리에서 변경이 가능하다.
4. 스레드 스케줄링
- 커널모드에서 스케줄러를 이용하여 실행해야 할 스레드들을 큐를 이용해 관리
- 기본적으로 스레드 우선순위에 따라 관리되고 상황에 따라 먼저 처리해야 하는 경우 디스패처를 통해 점유하여 CPU를 선점해 사용하게된다.
스레드 상태 정보
- 준비(Ready) : 실행할 준비가 된 상태, CreateThread를 호출하면 바로 준비상태가 되어 스레드 생성을 우선적으로 처리
- 실행(Running) : 스레드가 CPU를 할당받아 실행중인 상태. 퀀텀을 다 쓰거나 , 처리할 작업을 완료했거나 , 스레드가 자발적으로 전환했을 때 CPU가 실행을 멈추고 상태를 바꾼다.
- 실행 대기(Standby) : CPU할당 받았지만 아직 대기 중인 상태, 이러한 스레드는 CPU내 프로세서 당 하나만 존재하며 컨텍스트 스위칭을 통해 실행 상태로 바뀜
- 종료(Terminated) : 스레드의 모든 작업을 완료했거나 ExitThread 함수를 호출했을 때 종료 상태로 변경됨. 해당 스레드가 참조하는 핸들을 모두 닫고 스레드 소멸
- 대기(Waiting) : 실행중인 스레드가 Sleep과 같은 대기 함수를 만나 자발적으로 전환되어 스스로 대기 상태가 됨. 조건에 만족하거나 시간이 만료되면 준비상태로 전환됨
- 전이(Transition) : 대기 상태에서 간혹 물리적 메모리를 사용하지 않아 물리메모리를 할당하여야 하는 상태. 전이 상태에서 가상메모리로 페이징된 메모리가 물리 메모리에 올라오게 되면 대기상태가 된다.
- 지연 실행 대기 (Deferred Ready) : 프로세서 할당은 받았지만 아직 스케줄링이 되지 않은 상태. 비스타 이후 추가된 상태
스레드 스케줄링을 조정하는 경우
- 스레드가 퀀텀을 다 사용했을 때
- 입출력이 완료되었을 때
- 스레드 우선순위가 변경되었을 때
- 대기상태로 객체나 스레드가 변경되었을 때
- Sleep을 호출했을때
5. 스레드 동기화
- 스레드들이 서로 사용할 수 있는지를 확인하기 위해 상태 벙보를 주고 받는 것
- 이러한 이벤트 및 스레드 동기화하는 객체들을 디스패처에서 관리하기 때문에 디스패처 객체라고 한다
디스패처
- 커널에 존재하는 객체들 중 상태 정보를 통해 관리되는 객체들을 관리함
- 상태 신호라고 하는 시그널을 확인하며 현재의 처리흐름을 변경하거나 예외처리등의 작업을 수행
- 시그널 상태는 True/False가 있으며 True는 대기해야한다는 의미임
- 디스패처 객체 형식
- 프로세스
- 스레드
- 이벤트
- 뮤텍스
- 세마포어
- 타이머
- 파일
뮤텍스
- 커널모드에서 관리
- 코드에서 접근하는 객체는 뮤텍스가 접근가능한 상태에서만 사용이 가능하다.
뮤텍스의 특징
- 상호 배제를 기본으로 한다(객체를 동시에 사용할 수 없다)
- 하나의 스레드를 임계 구역을 사용하여 다른 객체가 해당 객체에 접근하지 못하도록 보호
- 자신이 처리해야할 작업을 완료하면 임계구역을 나오게 되고 뮤텍스가 사용가능한 상태로 할당을 해제한다.
- 이 상태가 되면 대기하던 객체가 임계구역으로 진입하게 되며 그 객체가 뮤텍스를 할당받는다
- Auto-Reset형태로 자원의 사용이 가능하면 자동으로 non signal상태가 된다.
세마포어
- 뮤텍스처럼 하나에게만 자원을 할당하지 않고 , 가능한 제한수를 설정하여 여러 객체에게 자원을 할당할 수 있다.
- 세마포어 최댓값이 1이라면 뮤텍스처럼 사용가능하다.
세마포어의 특징
- 리소스의 상태를 나타내는 카운터를 통해 관리
- 자원을 할당받게 되면 세마포어 카운터를 감소시켜 값을 낮춘다
- 세마포어 값이 0인 상태가 되면 자원을 할당받을 수 없게 되고 사용할 수 있을 때 까지 대기상태가 된다
- 자원 사용이 끝나면 세마포어 카운터를 증가시켜 대기 중인 상태로 사용할 수 있도록한다.
- Auto-Reset형태로 자원이 사용가능하면 자동으로 Non-signal 상태가 된다
이벤트
- 여러개의 스레드를 동시에 제어할 때 유용
- CreateEvent로 생성 가능
- 이벤트 발생 : SetEvent
- 이벤트 초기화(?) : ResetEvent
이벤트의 특징
- Bool변수를 통해 관리됨
- 이벤트 생성은 Manual-Reset모드와 Auto-Reset모드로 생성 가능함
- Manual-Reset의 경우 여러 스레드의 상태를 동시에 변경할 수 있으나 Auto-Reset은 하나만 가능
임계 영역(Critical Section)
- 뮤텍스와 비슷하지만 유저모드에서만 동작하기 때문에 프로세스 간 동기화에는 사용 불가능
임계 영역의 특징
- 일반적으로 뮤텍스를 통해 사용 가능
- 하나의 프로세스 내에서 스레드 간 동기화 하는데 사용
- 뮤텍스보다 가볍다
- CRITICAL_SECTION이라는 구조체를 이용해 관리
병렬 처리
- 기존에는 병렬처리를 위해 join & fork를 이용해 코드 작성
- c++ 11부터 Parallel Patterns Library(PPL) 제공
- 보통 앞에 parallel_로 시작한다 ex) for문을 병렬으로 실행하려면 parallel_for
'Programming > Windows' 카테고리의 다른 글
[WINDOWS] 프로세스 (0) | 2021.06.09 |
---|---|
[WINDOWS] 윈도우 기본 개념 (2) (0) | 2021.06.09 |
[WINDOWS] 윈도우 기본 개념 (1) (0) | 2021.06.09 |
[windbg] Windbg 사용법 / 덤프 분석 (0) | 2021.02.23 |
[windows] 프로세스와 스레드 (0) | 2021.02.13 |