11장 윈도우 스레드 풀

Preview:

Citation preview

11 장 윈도우 스레드 풀12 장 파이버

아꿈사 (http://cafe.naver.com/architect1)김홍준 (twitter.com/jun0683)

11 장 윈도우 스레드 풀- 비동기 함수 호출 ( 스레드 )- 시간 간격을 두고 함수 호출 ( 타이머 )- 커널 오브젝트가 시그널 되면 함수 호출 ( 이벤트 )- 비동기 I/O 요청 완료되면 함수 호출 (IOCP)

12 장 파이버

11 장 윈도우 스레드 풀- 비동기 함수 호출 ( 스레드 )- 시간 간격을 두고 함수 호출 ( 타이머 )- 커널 오브젝트가 시그널 되면 함수 호출 ( 이벤트 )- 비동기 I/O 요청 완료되면 함수 호출 (IOCP)

12 장 파이버

윈도우 스레드 풀이란 ? 스레드 생성 , 파괴 , 관리작업을 좀 더

쉽게구현 할 수 있도록 제공 ( 책에서는 비스타 이상 )

어렵지 않아요 ~

비동기 함수 호출 ( 스레드 ) 를 뙇 !

VOID NTAPI SimpleCallback( PTP_CALLBACK_INSTANCE pIn-stance, PVOID pvContext);

사용자 정의

BOOL TrySubmitThreadpoolCallback( PTP_SIMPLE_CALLBACK pfnCallback, PVOID pvContext, PTP_CALLBACK_ENVIRON pcbe);

사용자 정의 함수작업 요청 ( 비동기적으로 )

TrySubmitThreadpoolCallback()

이분을 쓰면 CreateThread X

스레드 일일이 생성 파괴 관리 X => 알아서 재사용 => 알아서 스레드 개수 증가 감소

명시적 작업 항목 제어

TrySubmitThreadpoolCallback 실패시( 메모리 부족 , 메모리 할당제한등 ..)

명시적 작업 항목 제어

스레드 풀에서 작업 항목이 들어 가지 않는다면 ?

내부적으로 작업 항목을 새로 생성 한 후작업 항목을 스레드 풀 큐에 넣음 => 작업 항목 큐를 이용하자 !

명시적으로 작업 항목을 제어 하려면1. 작업 항목 만들고2. 큐에 넣고

0. 작업 할 콜백함수 구현

1. 콜백 함수 원형 넣고 작업 항목 만듦

PTP_WORK CreateThreadpoolWork( PTP_WORK_CALLBACK pfnWorkHan-dler, PVOID pvContext, PTP_CALLBACK_ENVIRON pcbe);

VOID CALLBACK WorkCallback( PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work);

VOID SubmitThreadpoolWork(PTP_WORK pWork);

2. 큐에 넣기

명시적 작업 항목 제어

삽입한 장업항목을 취소하거나처리될때까지 특정 스레드를 대기상태

VOID WaitForThreadpoolWorkCall-backs(PTP_WORK pWork,BOOL bCancelPendingCallbacks);

True 면 취소 , 처리중이라면 취소하지 않고 처리될때 까지 대기False 면 완전히 처리 될떄까지 대기

명시적 작업 항목 제어

VOID CloseThreadpoolWork(PTP_WORK pwk);

작업 항목이 더 이상 필요 없다면작업 항목 제거

데모

11 장 윈도우 스레드 풀- 비동기 함수 호출 ( 스레드 )- 시간 간격을 두고 함수 호출 ( 타이머 )- 커널 오브젝트가 시그널 되면 함수 호출 ( 이벤트 )- 비동기 I/O 요청 완료되면 함수 호출 (IOCP)

12 장 파이버

시간 간격을 두고 함수 호출 ( 타이머 ) 를 뙇 !

VOID CALLBACK TimeoutCallback(PTP_CALLBACK_INSTANCE pInstance, PVOID pvContext,PTP_TIMER pTimer);

PTP_TIMER CreateThreadpoolTimer(PTP_TIMER_CALLBACK pfnTimerCall-back,PVOID pvContext,PTP_CALLBACK_ENVIRON pcbe)

타이머 함수 원형

타이머 생성

타이머 스레드 풀에 등록

VOID SetThreadpoolTimer(PTP_TIMER pTimer,PFILETIME pftDueTime,DWORD msPeriod,DWORD msWindowLength);

시간 간격을 두고 함수 호출

콜백 함수가 정확한 시간에 호출 해주는 것 보다 스레드를 깨웠다가 다시 대기 상태로 만드는 비용을 줄이는 것이 중요

타이머를 한번 만들고 SetThread-poolTimer()

을 이용해서 시간 조작

시간 간격을 두고 함수 호출

pftDueTime 을 NULL 로 넣으면타이머 호출 X타이머 오브젝트를 파괴 하지 않고 타이머 정지 가능

VOID SetThreadpoolTimer(PTP_TIMER pTimer,PFILETIME pftDueTime,DWORD msPeriod,DWORD msWindowLength);

시간 간격을 두고 함수 호출

삽입한 타이머을 취소하거나처리될때까지 특정 스레드를 대기상태

VOID WaitForThreadpoolTimerCall-backs(PTP_WORK pWork,BOOL bCancelPendingCallbacks);

True 면 취소 , 처리중이라면 취소하지 않고 처리될때 까지 대기False 면 완전히 처리 될떄까지 대기

11 장 윈도우 스레드 풀- 비동기 함수 호출 ( 스레드 )- 시간 간격을 두고 함수 호출 ( 타이머 )- 커널 오브젝트가 시그널 되면 함수 호출 ( 이벤트 )- 비동기 I/O 요청 완료되면 함수 호출 (IOCP)

12 장 파이버

커널 오브젝트가 시그널 되면 함수 호출( 이벤트 ) 를 뙇 !

VOID CALLBACK WaitCallback(PTP_CALLBACK_INSTANCE pInstance, PVOID Context,PTP_WAIT Wait,TP_WAIT_RESULT WaitResult);

PTP_WAIT CreateThreadpoolWait(PTP_WAIT_CALLBACK pfnWaitCall-back,PVOID pvContext,PTP_CALLBACK_ENVIRON pcbe);

VOID SetThreadpoolWait(PTP_WAIT pWaitItem,HANDLE hObject,PFILETIME pftTimeout);

시그널 대기 함수 원형

시그널 대기 함수 생성

스레드 풀에 등록

커널 오브젝트가 시그널 되면 함수 호출

핸들 오브젝트를 사용시그널 상태가 됬을 때 콜백 함수를 호출

VOID SetThreadpoolWait(PTP_WAIT pWaitItem,HANDLE hObject,PFILETIME pftTimeout);

커널 오브젝트가 시그널 되면 함수 호출

내부적으로 스레드 풀은WaitForMultipleObjects 을 이용하기 때문64 개만 대기 가능

동일한 커널 오브젝트를 동시에 여러 번사용이 안되므로 DuplicateHandle 을 이용복사된 핸들을 각각 등록

커널 오브젝트가 시그널 되면 함수 호출

프로세스 커널 오브젝트는 한번 시그널이면영원히 시그널 상태SetThreadpoolWait 호출할때 다른

오브젝트또는 Null 값을 전달해서 해당 핸들을 제거

커널 오브젝트가 시그널 되면 함수 호출

콜백 함수 내에서 WaitForThreadpoolWork호출 하면 데드락

SetThreadpoolWait 매개 변수로 전달한커널 오브젝트는 삭제 하면 안됨 !

커널 오브젝트가 시그널 되면 함수 호출

대기중인 커널 오브젝트에 대해PulseEvent 같은 시그널 함수 호출도 안됨 !해당 이벤트가 호출한 시점에 대기 하고 있음을 보장을 못함 !

11 장 윈도우 스레드 풀- 비동기 함수 호출 ( 스레드 )- 시간 간격을 두고 함수 호출 ( 타이머 )- 커널 오브젝트가 시그널 되면 함수 호출 ( 이벤트 )- 비동기 I/O 요청 완료되면 함수 호출 (IOCP)

12 장 파이버

비동기 I/O 요청 완료되면 함수 호출 (IOCP) 뙇 !

10 장에 대략적으로 다룸

어떤 함수를 호출 할지를 지정하기만 하면 됨

비동기 I/O 요청 완료되면 함수 호출 (IOCP)

VOID CALLBACK OverlappedComple-tionRoutine(PTP_CALLBACK_INSTANCE pInstance, PVOID pvContext,PVOID pOverlapped,ULONG IoResult,ULONG_PTR NumberOfBytesTrans-ferred,PTP_IO pIo);

I/O 작업 완료시 호출되는 함수 원형

PTP_IO CreateThreadpoolIo(HANDLE hDevice,PTP_WIN32_IO_CALLBACK pfnIoCall-back,PVOID pvContext,PTP_CALLBACK_ENVIRON pcbe);

스레드 풀 I/O 오브젝트 생성파일 / 장치 핸들값을 넣어줌

비동기 I/O 요청 완료되면 함수 호출 (IOCP)

VOID StartThreadpoolIo(PTP_IO pio);

VOID CancelThreadpoolIo(PTP_IO pio);

VOID CloseThreadpoolIo(PTP_IO pio);

단 , 풀에 넣고 나서 READ/WRITE 할것

I/O 오브젝트와 스레드 풀 연동

I/O 작업이 실패 하면 반드시 호출

사용을 마치려면 …I/O 오브젝트 닫기

비동기 I/O 요청 완료되면 함수 호출 (IOCP)

VOID WaitForThreadpoolIoCallbacks(PTP_IO pio,BOOL bCancelPendingCallbacks);

I/O 작업이 완료 될때까지 다른 스레드가 대기 시킴

True 면 시작 되지 않은 모든 요청을 취소 완료 통지도 발생 X

+@ 콜백 종료 동작

콜백 함수가 종료 될때 쓰면 유용

스레드 풀이 종료시 자동적으로 호출

LeaveCriticalSectionWhenCallbackReturns

ReleaseMutexWhenCallbackReturns

ReleaseSemaphoreWhenCallbackReturns

SetEventWhenCallbackReturns

FreeLibraryWhenCallbackReturns

스레드 풀 커스터마이징 뙇 !

스레드 풀에서 동작하는 스레드의 최소 최대 개수를 설정OR스레드 풀을 각각 독립적으로 생성 , 파괴

스레드 풀 커스터마이징

PTP_POOL CreateThreadpool(PVOID reserved);

BOOL SetThreadpoolThreadMinimum(PTP_POOL pThread-Pool, DWORD cthrdMin);BOOL SetThreadpoolThreadMaximum(PTP_POOL pThread-Pool, DWORD cthrdMost);

VOID CloseThreadpool(PTP_POOL pThreadPool);

기본 스레드 풀은 최소 스레드 1 개 최대 500 개를 가짐

11 장 윈도우 스레드 풀- 비동기 함수 호출 ( 스레드 )- 시간 간격을 두고 함수 호출 ( 타이머 )- 커널 오브젝트가 시그널 되면 함수 호출 ( 이벤트 )- 비동기 I/O 요청 완료되면 함수 호출 (IOCP)

12 장 파이버

파이버라 쓰고 코루틴이라 읽는다…

코루틴은 마치 예전 OS 의 비선점형 (non-preemptive) 쓰레드와 비슷하게 동작

프로그래머가 강제로 컨텍스트 스위칭 명령을 줘야 스위칭

파이버

기존 UNIX 프로그램을 포팅하기 위해서…윈도우는 그냥 스레드 쓰면 됨… .

유저모드에서 돌아서 가볍다스케줄링을 직접 해야 함

파이버 함수 사용

PVOID ConvertThreadToFiberEx(PVOID pvParam,DWORD dwFlags);

기존 스레드를 파이버로 변경

파이버 단위에는 부동소수점 상태 정보를 포함하지 않으므로플래그에 FIBER_FLAG_FLOAT_SWITCH 를 넣어줌

ConvertThreadToFiber

파이버 함수 사용

새로운 파이버를 생성리턴 받은 컨텍스트 정보를 저장 해두고 사용

PVOID CreateFiberEx(SIZE_T dwStackCommitSize,SIZE_T dwStackReserveSize,DWORD dwFlags,PFIBER_START_ROUTINE pStartAd-dress,PVOID pvParam);

VOID WINAPI FiberFunc(PVOID pvParam); 파이버 함수 원형

파이버 함수 사용

VOID SwitchToFiber(PVOID pvFiberExecutionCon-text);

바이퍼 간 스위칭

컨텍스트 정보를 이용해서 스위칭을 함

PVOID GetCurrentFiber(); 현재 컨텍스트 주소를 얻어옴

데모

끝 !

Recommended