스레드 풀
스레드 풀은 애플리케이션을 대신하여 비동기 콜백을 효율적으로 실행하는 작업자 스레드의 컬렉션입니다. 스레드 풀은 주로 애플리케이션 스레드 수를 줄이고 작업자 스레드의 관리를 제공하는 데 사용됩니다. 애플리케이션은 작업 항목을 큐에 대기하고, 대기 가능한 핸들과 작업을 연결하고, 타이머에 따라 자동으로 큐에 대기하고, I/O로 바인딩할 수 있습니다.
스레드 풀 아키텍처
다음 애플리케이션은 스레드 풀을 사용하면 이점을 얻을 수 있습니다.
- 매우 병렬이며 많은 수의 작은 작업 항목을 비동기적으로 디스패치할 수 있는 애플리케이션입니다(예: 분산 인덱스 검색 또는 네트워크 I/O).
- 각각 짧은 시간 동안 실행되는 많은 수의 스레드를 만들고 삭제하는 애플리케이션입니다. 스레드 풀을 사용하면 스레드 관리의 복잡성과 스레드 생성 및 소멸과 관련된 오버헤드를 줄일 수 있습니다.
- 백그라운드에서 병렬로 독립적인 작업 항목을 처리하는 애플리케이션(예: 여러 탭 로드).
- 커널 개체에서 단독 대기를 수행하거나 개체의 들어오는 이벤트를 차단해야 하는 애플리케이션입니다. 스레드 풀을 사용하면 컨텍스트 전환 수를 줄여 스레드 관리의 복잡성을 줄이고 성능을 높일 수 있습니다.
- 이벤트를 대기할 사용자 지정 웨이터 스레드를 만드는 애플리케이션입니다.
원래 스레드 풀은 Windows Vista에서 완전히 다시 아키텍처가 지정되었습니다. 새 스레드 풀은 단일 작업자 스레드 형식(I/O 및 비 I/O 모두 지원)을 제공하고, 타이머 스레드를 사용하지 않고, 단일 타이머 큐를 제공하고, 전용 영구 스레드를 제공하므로 개선되었습니다. 또한 정리 그룹, 더 높은 성능, 독립적으로 예약된 프로세스당 여러 풀 및 새 스레드 풀 API를 제공합니다.
스레드 풀 아키텍처는 다음으로 구성됩니다.
- 콜백 함수를 실행하는 작업자 스레드
- 여러 대기 핸들에서 대기하는 웨이터 스레드
- 작업 큐
- 각 프로세스에 대한 기본 스레드 풀
- 작업자 스레드를 관리하는 작업자 팩터리
좋은 연습 방법
새 스레드 풀 API는 원래 스레드 풀 API보다 더 많은 유연성과 제어를 제공합니다. 그러나 몇 가지 미묘하지만 중요한 차이점이 있습니다. 원래 API에서 대기 재설정은 자동으로 수행되었습니다. 새 API에서 대기는 매번 명시적으로 다시 설정되어야 합니다. 원래 API는 자동으로 가장을 처리하여 호출 프로세스의 보안 컨텍스트를 스레드로 전송합니다. 새 API를 사용하면 애플리케이션이 보안 컨텍스트를 명시적으로 설정해야 합니다.
다음은 스레드 풀을 사용하는 경우 모범 사례입니다.
프로세스의 스레드는 스레드 풀을 공유합니다. 단일 작업자 스레드는 한 번에 하나씩 여러 콜백 함수를 실행할 수 있습니다. 이러한 작업자 스레드는 스레드 풀에서 관리됩니다. 따라서 스레드에서 TerminateThread를 호출하거나 콜백 함수에서 ExitThread를 호출하여 스레드 풀에서 스레드를 종료하지 마세요.
I/O 요청은 스레드 풀의 모든 스레드에서 실행할 수 있습니다. 취소 함수가 I/O 요청을 처리하는 스레드와 다른 스레드에서 실행될 수 있으므로 스레드 풀 스레드에서 I/O를 취소하면 알 수 없는 작업이 취소될 수 있으므로 동기화가 필요합니다. 이를 방지하려면 항상 비동기 I/O에 대해 CancelIoEx를 호출할 때 I/O 요청이 시작된 OVERLAPPED 구조를 제공하거나 자체 동기화를 사용하여 CancelSynchronousIo 또는 CancelIoEx 함수를 호출하기 전에 대상 스레드에서 다른 I/O를 시작할 수 없도록 합니다.
함수에서 반환하기 전에 콜백 함수에서 만든 모든 리소스를 정리합니다. 여기에는 TLS, 보안 컨텍스트, 스레드 우선 순위 및 COM 등록이 포함됩니다. 콜백 함수는 반환하기 전에 스레드 상태를 복원해야 합니다.
스레드 풀이 핸들로 완료되었다는 신호를 보낼 때까지 대기 핸들과 연결된 개체를 활성 상태로 유지합니다.
긴 작업(예: I/O 플러시 또는 리소스 정리)에서 대기 중인 모든 스레드를 표시하여 스레드 풀이 이 스레드를 기다리는 대신 새 스레드를 할당할 수 있도록 합니다.
스레드 풀을 사용하는 DLL을 언로드하기 전에 모든 작업 항목, I/O, 대기 작업 및 타이머를 취소하고 콜백 실행이 완료되기를 기다립니다.
콜백이 완료되기를 기다리지 않도록 하고 스레드 우선 순위를 유지하여 작업 항목과 콜백 간의 종속성을 제거하여 교착 상태를 방지합니다.
기본 스레드 풀을 사용하는 다른 구성 요소와 함께 프로세스에서 너무 많은 항목을 너무 빨리 큐에 대기하지 마세요. Svchost.exe 포함하여 프로세스당 하나의 기본 스레드 풀이 있습니다. 기본적으로 각 스레드 풀에는 최대 500개의 작업자 스레드가 있습니다. 스레드 풀은 준비/실행 상태의 작업자 스레드 수가 프로세서 수보다 적어야 하는 경우 더 많은 작업자 스레드를 만들려고 시도합니다.
COM 단일 스레드 아파트 모델은 스레드 풀과 호환되지 않으므로 방지합니다. STA는 스레드의 다음 작업 항목에 영향을 줄 수 있는 스레드 상태를 만듭니다. STA는 일반적으로 수명이 길며 스레드 선호도가 있으며 스레드 풀과 반대입니다.
스레드 우선 순위 및 격리를 제어하고, 사용자 지정 특성을 만들고, 응답성을 향상시키는 새 스레드 풀을 만듭니다. 그러나 추가 스레드 풀에는 더 많은 시스템 리소스(스레드, 커널 메모리)가 필요합니다. 풀이 너무 많을수록 CPU 경합 가능성이 높아질 수 있습니다.
가능하면 APC 기반 메커니즘 대신 대기 가능한 개체를 사용하여 스레드 풀 스레드에 신호를 보낼 수 있습니다. 시스템이 스레드 풀 스레드의 수명을 제어하므로 알림이 전달되기 전에 스레드를 종료할 수 있으므로 API는 다른 신호 메커니즘과 마찬가지로 스레드 풀 스레드에서도 잘 작동하지 않습니다.
스레드 풀 디버거 확장 !tp를 사용합니다. 이 명령에는 다음과 같은 사용법이 있습니다.
- 풀 주소 플래그
- obj 주소 플래그
- tqueue 주소 플래그
- 웨이터 주소
- 작업자 주소
풀, 웨이터 및 작업자의 경우 주소가 0이면 명령은 모든 개체를 덤프합니다. 웨이터 및 작업자의 경우 주소를 생략하면 현재 스레드가 덤프됩니다. 0x1(한 줄 출력), 0x2(덤프 멤버) 및 0x4(덤프 풀 작업 큐)의 플래그가 정의됩니다.
관련 항목