https://www.hanbit.co.kr/store/books/look.php?p_code=B2974835990
제프리 리처의 Windows via C/C++(복간판)
이 책은 윈도우 XP, 윈도우 비스타, 윈도우 서버 2008까지 내용을 포괄한다. 이미 윈도우 10이 출시된 지 오래지만 윈도우의 기본 구조는 변하지 않아 아직까지도 이 책은 윈도우 시스템 프로그래
www.hanbit.co.kr
해당 책을 읽고 학습 목적으로 간단하게 정리한 글입니다.
개요
Windows OS는 preemptive OS이기 때문에 이를 이해하기 위해 스케줄링에 대한 이해도 필요하다.
일반적으로 Windows는 20ms정도 마다 thread를 선택하여 context switch한다.
Windows는 언제나 특정 Thread를 정지하고 다른 Thread를 수행할 수 있다.
이로 인해 선점형 멀티스레드 기반 운영체제 (preemptive multithreaded operating system)이라고 불린다.
또한 따라서 생성한 스레드가 어느 시점에 수행된다는 것을 보장받을 수 없다.
(+ 주어진 시간 내에 스레드를 수행시키는 것도 불가능)
스레드의 정지와 계속 수행
Thread는 suspend count가 있다. 생성되었을 때 해당 값은 1이며 만약 CreateThread에 CREATE_SUSPENDED플래그가 전달되지 않았다면 count를 0으로 만든다.
만약 count가 1이라면 Thread는 스케줄 불가능 상태이다.
SuspendThread를 통해 thread의 suspend count를 1 증가시킬 수 있다.
ResumeThread를 통해 thread의 suspend count를 1 감소시킬 수 있다.
이 뜻은 suspend count가 0인 thread를 suspend thread를 3번 반복시켜 count를 3으로 만들었다면 resume thread도 3번 호출해야 정상적으로 thread가 스케줄링 된다는 것이다.
SuspendThread를 통해 정지된 스레드가 힙 메모리 할당 중에 정지된다면 해당 스레드가 resume되기 전까지는 다른 thread가 힙에 접근하려 할 때 정지된다.
따라서 Suspend 자체는 명확한 상황에서 사용해야 한다.
프로세스의 정지와 계속 수행
윈도우에서 실행 단위는 스레드이기 때문에 프로세스를 멈춘다는 의미 자체는 없지만
프로세스를 멈춘다는 것은 프로세스 내의 모든 스레드를 정지시킨다는 의미로 사용된다.
하지만 윈도우는 race condition이 일어날 수 있기 때문에 프로세스의 모든 스레드를 정지시키는 방법을 제공하지 않는다.
CreateToolhelp32Snapshot을 사용해 특정 시점의 thread 목록을 받아 각각 정지시키는 코드를 만들 수는 있다.
다만 해당 함수가 실행되는 도중 스레드는 새로 만들어지거나 없어질 수 있다는 것을 주의해야 한다.
슬리핑
Thread는 Sleep함수를 통해 특정 시간(ms)동안 스케줄하지 않도록 커널에 요청할 수 있다.
시간 인자에 INFINITE를 전달할 수도 있다.(영원히 스케줄링 되지않기 때문에 실제로 사용될 일이 없다.)
시간 인자에 0을 전달한다면 해당 시점에서 남은 타임 슬라이스를 포기하고 다른 스레드가 스케줄링 될 수 있도록 한다. (priority에 따라 본인이 다시 스케줄링 될 수 있다.)
다른 스레드로의 전환
SwitchToThread함수를 통해 Thread전환이 가능하다.
이 때 Sleep과는 다르게 CPU 시간을 받지 못해 수행되지 못했던 스레드가 대상이므로, 함수를 호출한 thread보다 낮은 priority를 가진 스레드의 실행도 가능하다.
스레드 수행 시간
시간 측정을 위한 함수들이 있지만 Thread의 정확한 수행시간을 측정하기는 어렵다.
GetThreadTimes를 사용하면 Thread의 생성, 종료, 커널, 유저 시간을 획득할 수 있다.
GetThreadTimes 함수(processthreadsapi.h) - Win32 apps
지정된 스레드에 대한 타이밍 정보를 검색합니다.
learn.microsoft.com
프로세서의 주파수 등의 이유로 시간은 다르게 측정될 수도 있다.
https://basaeng.tistory.com/28
컴퓨터의 시간측정
개요코드의 성능 측정을 위해 시작 끝 지점의 시간을 구해서 사용하거나, n초 후에 어떤 로직을 실행해야 하는 등 코드를 만들 때 시간을 측정해야 하는 경우가 있다. 이 때 시간을 어떻게 받아
basaeng.tistory.com
컨텍스트 내의 CONTEXT 구조체
스레드 스케줄링은 이름이 context switching인 것 처럼 context가 중요하다.
https://learn.microsoft.com/ko-kr/windows/win32/api/winnt/ns-winnt-context
CONTEXT(winnt.h) - Win32 apps
프로세서별 레지스터 데이터를 포함합니다. 시스템은 CONTEXT 구조를 사용하여 다양한 내부 작업을 수행합니다. (CONTEXT)
learn.microsoft.com
GetThreadContext를 호출하면 특정 컨텍스트 정보 값을 가져올 수 있다.
다만 실행중에 가져오면 측정 값과 실제 상태가 다를 수 있기 때문에 SuspendThread 이후 호출하는 것이 권장된다.
물론 정지되는 스레드(얻으려는 정보를 가진 스레드)와 컨텍스트 정보를 확인하는 스레드는 다르다.
스레드 우선순위
스레드 스케줄링은 priority 기반으로 된다.
prioity는 0에서 31 번호를 가진다 숫자가 커질 수록(31에 가까울 수록) 높은 우선순위이다.
우선순위가 높은 스레드들이 계속해서 존재한다면 상대적으로 우선순위가 낮은 스레드는 starvation상태에 놓일 수 있다.
다만 대부분의 스레드들은 스케줄 불가능 상태를 유지하며 starvation을 방지하기 위한 몇가지 알고리즘이 있다.
우선순위의 추상적인 의미
MS 개발자들은 추후에 발전될 스케줄링 알고리즘을 위해 추상적인 API를 제공했다.
개발자가 설정 가능한 프로세스, 스레드 우선순위 클래스이다.
https://learn.microsoft.com/ko-kr/windows/win32/procthread/scheduling-priorities
일정 우선 순위 - Win32 apps
스레드는 예약 우선 순위에 따라 실행되도록 예약됩니다.
learn.microsoft.com
거의 모든 프로세스는 Normal상태에서 실행된다.
선호도
선호도는 특정 프로그램이 어떤 CPU에서 더 수행될 가능성이 높은 것을 말한다.
일반적으로 윈도우는 소프트 선호도(affinity)를 사용한다.
다른 조건이 같다면 최근 수행한 CPU에서 수행하는 것이다.
캐시 등의 리소스를 재사용할 수 있기 때문에 유용하다.
SetProcessAffinityMask를 사용하면 특정 프로세스의 선호도를 지정해 일부 CPU에서만 프로그램이 수행되도록 할 수 있다.
GetProcessAffinityMask를 통해 선호도 마스크 값을 얻을 수도 있다.
선호도 값은 상속되어 차일드 프로세스에게 전이될 수 있다.
작업 관리자에서 프로세서 선호도를 지정할 수도 있다.
NUMA(Non-Uniform Memory Access)구조에서는 각 보드마다 CPU set과 메모리가 존재한다.
하나의 보드 내의 CPU를 통해서만 접근한다면 성능적으로 이점을 볼 수 있기 때문에 이 때 선호도를 사용해볼 수 있다.
'C, C++ > WINDOWS VIA C,C++' 카테고리의 다른 글
[WINDOWS VIA C/C++] 08. 유저 모드에서의 스레드 동기화 (2) | 2025.08.29 |
---|---|
[WINDOWS VIA C/C++] 05.잡 (0) | 2025.08.21 |
[WINDOWS VIA C/C++] 04.프로세스 (0) | 2025.08.19 |
[WINDOWS VIA C/C++] 03.커널 오브젝트 (2) | 2025.08.14 |
[WINDOWS VIA C/C++] 02.문자와 문자열로 작업하기 (2) | 2025.08.14 |