SlideShare a Scribd company logo
3
Most read
4
Most read
7
Most read
IOCP IO Completion Port
NHN NEXT
남현욱
동작 원리
IOCP의 목적
IO 작업에서 동시 수행되는 스레드 개수의 상한을 설정하자!
그래서 CPU 자원을 최대한 효율적으로 사용하자!
동작 원리
IOCP 생성
당연히 IOCP를 쓰려면 먼저 IOCP를 만들어야한다.
원형
CreateIoCompletionPort(
HANDLE fileHandle, 		 	 // IOCP와 연결할 핸들. 첫 생성시는
						 		 // INVALID_HANDLE_VALUE 넘김
HANDLE ExistingCompletionPort, //IOCP 핸들. 역시 첫 생성시는 NULL.
ULONG_PTR CompletionKey, 		 //IO 완료시 넘어갈 값. 사용자가 넘기고 싶은 값 넘김.
DWORD NumberOfConcurrentThreads //한 번에 동작할 수 있는 최대 스레드 개수.
									 //0 넘기면 프로세서 숫자로 자동 지정됨.
동작 원리
IO 장치와 IOCP 연결 - 마찬가지로 CreateIoCompletionPort를 쓴다.
HANDLE
HANDLE hPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
HANDLE port = CreateIoCompletionPort(socket,hPort,(ULONG_PTR)id,0);
//error
if(port != hPort) return false;
장치 리스트
새로운 레코드
추가
hDevice CompletionKey
레코드 추가 시점
CreateIoCompletionPort 함수로 장치 연결시
레코드 삭제 시점
해당 장치의 핸들이 닫혔을 때
CreateIoCompletionPort를 호출하
면 내부적으로 IOCP와 연결된 여러 장
치들을 관리하기 위한 장치 리스트에 새
로운 레코드를 추가한다.
동작 원리
장치와 연결이 끝나면 IO 작업이 완료된 후 완료된 IO에 대한 처리를 수행
할 스레드 풀을 구성한다. 일반적으로 스레드 풀의 크기는 프로세서 개수의
2배 정도를 할당한다(이유는 이후 구조 설명 후 다시 살펴보자).
for(int i = 0; i < ioThreadCount; i++)
{
	 DWORD ThreadId;
	 HANDLE hThread = (HANDLE)_beginthreadex(NULL,0, workerThread,
									(LPVOID)i,0,(unsinged int)&dwThreadId);
}
동작 원리
IO Completion Queue
dwNumberOfBytes
Transferred
dwCompletionKey lpOverlapped dwError
레코드 추가 시점
I/O 요청이 완료되었을 때
PostQueuedCompletionStatus 함수 호출시
레코드 삭제 시점
IO completion Port가 Wait Thread Queue의 항목을 가져올 때
즉 이 큐는 IOCP와 연결한 device의 IO 작업이 끝났음을 알려주는 큐이다.
방금 전 생성한 스레드 풀에서 적절한 스레드들이 IO Completion Queue
에서 작업거리를 꺼내 IO 완료에 따른 처리를 수행하게 된다.
동작 원리
Waiting Thread Queue(*LIFO)
dwThreadId
레코드 추가 시점
GetQueuedCompletionStatus 함수가 호출되었을 때
레코드 삭제 시점
IO Completion Queue가 비어있지 않고 수행 중인 스레드의 개수가 동시 수행 가능한 스레드 개수를 초과하지 않은 경우
이 큐는 IO 작업의 완료를 처리하기 위해 대기하고 있는 스레드들의
큐이다. GetQueuedCompletionStatus 함수를 호출했을 때 당장 IO
Completion Queue에 항목이 없거나 동시 수행 가능한 스레드 개수를
초과한 경우 대기 큐에 들어가 대기하고 있다가 적당한 상황이 오면
깨어나서 IO 완료에 대한 처리를 수행하게 된다.
동작 원리
Release Thread List
dwThreadId
레코드 추가 시점
IO Completion Port가 Waiting Thread Queue에 있는 스레드를 깨우는 경우
일시정지되었던 스레드가 다시 깨어났을 경우
레코드 삭제 시점
스레드가 다시 GetQueuedCompletionStatus 함수를 호출했을 때
스레드가 정지되는 함수를 호출했을 때
실제 IO 완료에 따른 처리를 수행하기 위해 깨어나서 돌고 있는 Thread
들의 리스트이다. IOCP에서 지정한 개수만큼의 스레드만 이 리스트에 속할
수 있다(그 만큼만 깨어있을 수 있다).
동작 원리
Paused Thread List
dwThreadId
레코드 추가 시점
수행 중이던 스레드가 스레드의 정지시키는 함수를 호출했을 때
레코드 삭제 시점
일시정지되었던 스레드가 다시 깨어날 경우
작업을 처리하던 스레드가 특정 함수의 호출(스레드를 블락시키는 함수 등)
했을 때 이 스레드를 Paused Thread List로 보낸다.
예시
장치 리스트
socket
프로세서가 2개인 컴퓨터에서 socket과 연결된 IOCP가 하나 있
다고 가정할 때 IOCP의 동작을 통해 구조를 이해해보자.
예시
장치 리스트
socket
아직 완료된 IO 작업이 없으므로 IO Completion Queue는 비
어있는 상태일 것이다.
IO Completion Queue
예시
장치 리스트
socket
Waiting Thread Queue에는 처음 생성한 스레드 풀에서
GetQueuedCompletionStatus 함수 호출을 통해 들어간 4개
의 스레드가 대기중인 상황이다.
IO Completion Queue
Waiting Thread Queue
Thread 1 Thread 2 Thread 3 Thread 4
예시
장치 리스트
socket
아직 완료된 IO 작업이 없으니 Release Thread List와 Pause
Thread List도 비어있는 상태.
IO Completion Queue
Waiting Thread Queue
Thread 1 Thread 2 Thread 3 Thread 4
Release Thread List
Pause Thread List
예시
장치 리스트
socket
이 때 2개의 IO 작업이 완료되었다고 하자.
IO Completion Queue
Waiting Thread Queue
Thread 1 Thread 2 Thread 3 Thread 4
Release Thread List
Pause Thread List
Completion 1 Completion 2
예시
장치 리스트
socket
IO Completion을 처리하기 위해 Waiting Thread Queue
에 가장 최근에 들어온 스레드 2개를 깨우게 된다(Waiting
Thread Queue는 성능을 위해 LIFO 순으로 Thread를 꺼낸
다).
IO Completion Queue
Waiting Thread Queue
Thread 1 Thread 2 Thread 3 Thread 4
Release Thread List
Pause Thread List
Thread 4 Thread 3
예시
장치 리스트
socket
Release Thread List에 2개가 돌고 있을 때, 또 다시 새로운 IO
작업이 완료되었다고 하자. 이 때 이미 Relase Thread List에 2
개의 Thread가 돌고 있기 때문에 새로운 스레드는 깨우지 않는
다.
IO Completion Queue
Waiting Thread Queue
Thread 1 Thread 2
Release Thread List
Pause Thread List
Thread 4 Thread 3
Completion 3 Completion4
예시
장치 리스트
socket
이 때 Thread4에서 어떤 함수가 호출되어 이 Thread가 대기 상
태에 빠지게 된다면 어떻게 될까?
IO Completion Queue
Waiting Thread Queue
Thread 1 Thread 2
Release Thread List
Pause Thread List
Thread 4 Thread 3
Completion 3 Completion4
Thread 4
예시
장치 리스트
socket
IOCP는 항상 스레드 개수를 사용할 수 있는 한 많이 사용하려
고 한다. 그래서 이 경우 1개만 돌고 있으므로 Waiting Thread
Queue에서 새로운 스레드를 꺼낸다(이 때문에 프로세서 개수
보다 많은 스레드가 필요한 것이다!).
IO Completion Queue
Waiting Thread Queue
Thread 1 Thread 2
Release Thread List
Pause Thread List
Thread 3
Completion 4
Thread 4
Thread 2
예시
장치 리스트
socket
그런데 이 상태에서 Pause Thread List의 스레드가 대기 상태
의 작업이 끝난다면? 이 걸 그냥 깨우면 Release Thread List의
최대 Thread 개수를 초과하게 되어버린다.
IO Completion Queue
Waiting Thread Queue
Thread 1
Release Thread List
Pause Thread List
Thread 3
Completion 4
Thread 4
Thread 2
이제 대기 상태 끝!
예시
장치 리스트
socket
그래서 이 경우 IOCP는 Release Thread List의 스레드가 다시
대기 상태에 들어가기 전까진 스레드를 깨우지 않는다.
IO Completion Queue
Waiting Thread Queue
Thread 1
Release Thread List
Pause Thread List
Thread 3
Completion 4
Thread 4
Thread 2
불가능!
코드(GQCS/PQCS)
각각의 IO Worker Thread에서는 아래와 같은 코드를 수행해서 IO 완료에 따른 처리를 하게 된다.
while(true)
{
	 int ret = GetQueuedCompletionStatus(port,&numBytes,&completionKey,&overlapped,TIME_OUT);
	
	 if(ret == 0 && GetLastError() == WAIT_TIMEOUT)
		continue;	
	//그 외 경우 에러 처리는 생략. overlapped가 nullptr이라든가 numBytes가 이상하다든가 하는 경우들이 있음. 보통 연결 종료.
	//completionKey가 종료된 IO작업 종류를 담고 있다고 가정
	 if(completionKey == IO_RECV)
	{
		//recv 관련 작업 수행
	}
	 else if(completionKey == IO_SEND)
	{
		//send 관련 작업 수행
	}
}
PQCS는 IO Completion Queue에 새 요소를 집어넣을 수 있게 해준다. 다른 스레드에 뭔가 완료
통지를 보내고 싶을 때 유용. 인자는 GQCS와 거의 동일(GQCS 호출시 필요한 데이터 거의 그대로
넘김)
//example. 대기중인 다른 스레드 종료시키기(THREAD_RELEASE가 스레드 종료 이벤트라고 가정).
PostQueuedCompletionStatus(port, 100, THREAD_RELEASE , overlapped);
코드(SEND/RECV)
send, recv를 호출하는 부분에서는 아래와 같은 방식으로 코드를 작성하게 된다.
WSARecv(clntSock,			//클라이언트 소켓.
	&ioContext->wsaBuf,		//읽을 데이터 버퍼의 포인터.
	1,					//데이터 입력 버퍼의 개수.
	nullptr,				//recv 결과 읽은 바이트 수. IOCP에서는 비동기 방식으로 사용하지 않으므로 nullptr 넘겨도 무방.
	 &flags,	 	 	 	 //recv에 사용될 플래그.
	 &ioContext->overlapped),	//OVERLAPPED 구조체의 포인터
	nullptr);				//completion routine 함수의 포인터. IOCP에서는 사용하지 않으므로 nullptr 넘겨도 무방.
WSARecv(clntSock,
	&ioContext->wsaBuf,
	1,
	nullptr,
	0,
	&ioContext->overlapped),
	nullptr);
recv나 send나 거의 똑같다. io 작업을 위한 버퍼와 OVERLAPPED 구조체의 포인터를 넘겨준다.

More Related Content

What's hot (20)

PPTX
Overlapped IO와 IOCP 조사 발표
Kwen Won Lee
 
PDF
게임서버프로그래밍 #1 - IOCP
Seungmo Koo
 
PDF
Multiplayer Game Sync Techniques through CAP theorem
Seungmo Koo
 
PDF
Windows Registered I/O (RIO) vs IOCP
Seungmo Koo
 
PDF
NDC12_Lockless게임서버설계와구현
noerror
 
PPTX
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기
강 민우
 
PPTX
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
YEONG-CHEON YOU
 
PDF
[NDC2016] TERA 서버의 Modern C++ 활용기
Sang Heon Lee
 
PDF
실시간 게임 서버 최적화 전략
YEONG-CHEON YOU
 
PDF
테라로 살펴본 MMORPG의 논타겟팅 시스템
QooJuice
 
PPT
Multithread & shared_ptr
내훈 정
 
PDF
Ndc2014 시즌 2 : 멀티쓰레드 프로그래밍이 왜 이리 힘드나요? (Lock-free에서 Transactional Memory까지)
내훈 정
 
PDF
[야생의 땅: 듀랑고] 서버 아키텍처 - SPOF 없는 분산 MMORPG 서버
Heungsub Lee
 
PDF
조정훈, 게임 프로그래머를 위한 클래스 설계, NDC2012
devCAT Studio, NEXON
 
PDF
레퍼런스만 알면 언리얼 엔진이 제대로 보인다
Lee Dustin
 
PDF
게임서버프로그래밍 #4 - 멀티스레드 프로그래밍
Seungmo Koo
 
PDF
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019
devCAT Studio, NEXON
 
PDF
[야생의 땅: 듀랑고] 서버 아키텍처 Vol. 2 (자막)
Heungsub Lee
 
PDF
잘 알려지지 않은 숨은 진주, Winsock API - WSAPoll, Fast Loopback
흥배 최
 
PDF
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
Seungmo Koo
 
Overlapped IO와 IOCP 조사 발표
Kwen Won Lee
 
게임서버프로그래밍 #1 - IOCP
Seungmo Koo
 
Multiplayer Game Sync Techniques through CAP theorem
Seungmo Koo
 
Windows Registered I/O (RIO) vs IOCP
Seungmo Koo
 
NDC12_Lockless게임서버설계와구현
noerror
 
[IGC 2017] 펄어비스 민경인 - Mmorpg를 위한 voxel 기반 네비게이션 라이브러리 개발기
강 민우
 
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
YEONG-CHEON YOU
 
[NDC2016] TERA 서버의 Modern C++ 활용기
Sang Heon Lee
 
실시간 게임 서버 최적화 전략
YEONG-CHEON YOU
 
테라로 살펴본 MMORPG의 논타겟팅 시스템
QooJuice
 
Multithread & shared_ptr
내훈 정
 
Ndc2014 시즌 2 : 멀티쓰레드 프로그래밍이 왜 이리 힘드나요? (Lock-free에서 Transactional Memory까지)
내훈 정
 
[야생의 땅: 듀랑고] 서버 아키텍처 - SPOF 없는 분산 MMORPG 서버
Heungsub Lee
 
조정훈, 게임 프로그래머를 위한 클래스 설계, NDC2012
devCAT Studio, NEXON
 
레퍼런스만 알면 언리얼 엔진이 제대로 보인다
Lee Dustin
 
게임서버프로그래밍 #4 - 멀티스레드 프로그래밍
Seungmo Koo
 
이무림, Enum의 Boxing을 어찌할꼬? 편리하고 성능좋게 Enum 사용하기, NDC2019
devCAT Studio, NEXON
 
[야생의 땅: 듀랑고] 서버 아키텍처 Vol. 2 (자막)
Heungsub Lee
 
잘 알려지지 않은 숨은 진주, Winsock API - WSAPoll, Fast Loopback
흥배 최
 
게임서버프로그래밍 #0 - TCP 및 이벤트 통지모델
Seungmo Koo
 

Viewers also liked (6)

PDF
게임서버프로그래밍 #2 - IOCP Adv
Seungmo Koo
 
PDF
[KGC 2012]Boost.asio를 이용한 네트웍 프로그래밍
흥배 최
 
PDF
게임서버프로그래밍 #8 - 성능 평가
Seungmo Koo
 
PDF
게임서버프로그래밍 #7 - 패킷핸들링 및 암호화
Seungmo Koo
 
PDF
게임서버프로그래밍 #6 - 예외처리 및 로깅
Seungmo Koo
 
PDF
서버 개발자가 되기 위한 첫 걸음
nexusz99
 
게임서버프로그래밍 #2 - IOCP Adv
Seungmo Koo
 
[KGC 2012]Boost.asio를 이용한 네트웍 프로그래밍
흥배 최
 
게임서버프로그래밍 #8 - 성능 평가
Seungmo Koo
 
게임서버프로그래밍 #7 - 패킷핸들링 및 암호화
Seungmo Koo
 
게임서버프로그래밍 #6 - 예외처리 및 로깅
Seungmo Koo
 
서버 개발자가 되기 위한 첫 걸음
nexusz99
 
Ad

Similar to Iocp 기본 구조 이해 (20)

PDF
Undertow RequestBufferingHandler 소개
Ted Won
 
PPT
GCGC- CGCII 서버 엔진에 적용된 기술 (4) - Executing System
상현 조
 
PPTX
Windows via C/C++ Chapter 10
iluvs
 
PDF
R2서버정진욱
jungjinwouk
 
PDF
[25]안드로이드에서 코루틴은 어떻게 적용할 수 있을까?: 코루틴 적용 및 ReactiveX(RxJava/RxKotlin)와 비교한다면?
NAVER Engineering
 
PPT
Gcd ppt
Sangon Lee
 
PDF
android_thread
handfoot
 
PDF
[2D4]Python에서의 동시성_병렬성
NAVER D2
 
PPTX
11장 윈도우 스레드 풀 + 12장 파이버
홍준 김
 
PPTX
11장 윈도우 스레드 풀
홍준 김
 
PPTX
Windosw via c 스터디23장.pptx
HolyTak
 
PPTX
Windosw via c 스터디23장.pptx
HolyTak
 
PPTX
Eddy_description.pptx
Kim Sanghoon
 
PDF
Blockchain Study(4) - Geth & Smart Contract
Fermat Jade
 
PDF
Lock free queue
Bongseok Cho
 
PPTX
Wire shark 사용법 및 네트워크 개론 살짝 설명
진우 이
 
PPTX
11 윈도우스레드풀
ssuser0c2478
 
PDF
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
sung ki choi
 
PPTX
Node week1
은석 김은석
 
PPTX
Concurrent programming 2
Byeongsu Kang
 
Undertow RequestBufferingHandler 소개
Ted Won
 
GCGC- CGCII 서버 엔진에 적용된 기술 (4) - Executing System
상현 조
 
Windows via C/C++ Chapter 10
iluvs
 
R2서버정진욱
jungjinwouk
 
[25]안드로이드에서 코루틴은 어떻게 적용할 수 있을까?: 코루틴 적용 및 ReactiveX(RxJava/RxKotlin)와 비교한다면?
NAVER Engineering
 
Gcd ppt
Sangon Lee
 
android_thread
handfoot
 
[2D4]Python에서의 동시성_병렬성
NAVER D2
 
11장 윈도우 스레드 풀 + 12장 파이버
홍준 김
 
11장 윈도우 스레드 풀
홍준 김
 
Windosw via c 스터디23장.pptx
HolyTak
 
Windosw via c 스터디23장.pptx
HolyTak
 
Eddy_description.pptx
Kim Sanghoon
 
Blockchain Study(4) - Geth & Smart Contract
Fermat Jade
 
Lock free queue
Bongseok Cho
 
Wire shark 사용법 및 네트워크 개론 살짝 설명
진우 이
 
11 윈도우스레드풀
ssuser0c2478
 
제프리 리처의 Windows via C/C++ : 8장 유저 모드에서의 스레드 동기화
sung ki choi
 
Node week1
은석 김은석
 
Concurrent programming 2
Byeongsu Kang
 
Ad

More from Nam Hyeonuk (20)

PPTX
Next 게임 실전 프로젝트 슬라이드
Nam Hyeonuk
 
PDF
Haskell study 15
Nam Hyeonuk
 
PDF
Haskell study 14
Nam Hyeonuk
 
PDF
Haskell study 13
Nam Hyeonuk
 
PDF
Haskell study 12
Nam Hyeonuk
 
PDF
Haskell study 11
Nam Hyeonuk
 
PDF
Haskell study 10
Nam Hyeonuk
 
PDF
Haskell study 9
Nam Hyeonuk
 
PDF
Haskell study 8
Nam Hyeonuk
 
PDF
Haskell study 7
Nam Hyeonuk
 
PDF
Haskell study 6
Nam Hyeonuk
 
PDF
Haskell study 5
Nam Hyeonuk
 
PDF
Haskell study 4
Nam Hyeonuk
 
PDF
Haskell study 3
Nam Hyeonuk
 
PDF
Haskell study 2
Nam Hyeonuk
 
PDF
Haskell study 1
Nam Hyeonuk
 
PDF
Haskell study 0
Nam Hyeonuk
 
PDF
Multi thread
Nam Hyeonuk
 
PDF
Memory & object pooling
Nam Hyeonuk
 
PDF
Database
Nam Hyeonuk
 
Next 게임 실전 프로젝트 슬라이드
Nam Hyeonuk
 
Haskell study 15
Nam Hyeonuk
 
Haskell study 14
Nam Hyeonuk
 
Haskell study 13
Nam Hyeonuk
 
Haskell study 12
Nam Hyeonuk
 
Haskell study 11
Nam Hyeonuk
 
Haskell study 10
Nam Hyeonuk
 
Haskell study 9
Nam Hyeonuk
 
Haskell study 8
Nam Hyeonuk
 
Haskell study 7
Nam Hyeonuk
 
Haskell study 6
Nam Hyeonuk
 
Haskell study 5
Nam Hyeonuk
 
Haskell study 4
Nam Hyeonuk
 
Haskell study 3
Nam Hyeonuk
 
Haskell study 2
Nam Hyeonuk
 
Haskell study 1
Nam Hyeonuk
 
Haskell study 0
Nam Hyeonuk
 
Multi thread
Nam Hyeonuk
 
Memory & object pooling
Nam Hyeonuk
 
Database
Nam Hyeonuk
 

Iocp 기본 구조 이해

  • 1. IOCP IO Completion Port NHN NEXT 남현욱
  • 2. 동작 원리 IOCP의 목적 IO 작업에서 동시 수행되는 스레드 개수의 상한을 설정하자! 그래서 CPU 자원을 최대한 효율적으로 사용하자!
  • 3. 동작 원리 IOCP 생성 당연히 IOCP를 쓰려면 먼저 IOCP를 만들어야한다. 원형 CreateIoCompletionPort( HANDLE fileHandle, // IOCP와 연결할 핸들. 첫 생성시는 // INVALID_HANDLE_VALUE 넘김 HANDLE ExistingCompletionPort, //IOCP 핸들. 역시 첫 생성시는 NULL. ULONG_PTR CompletionKey, //IO 완료시 넘어갈 값. 사용자가 넘기고 싶은 값 넘김. DWORD NumberOfConcurrentThreads //한 번에 동작할 수 있는 최대 스레드 개수. //0 넘기면 프로세서 숫자로 자동 지정됨.
  • 4. 동작 원리 IO 장치와 IOCP 연결 - 마찬가지로 CreateIoCompletionPort를 쓴다. HANDLE HANDLE hPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0); HANDLE port = CreateIoCompletionPort(socket,hPort,(ULONG_PTR)id,0); //error if(port != hPort) return false; 장치 리스트 새로운 레코드 추가 hDevice CompletionKey 레코드 추가 시점 CreateIoCompletionPort 함수로 장치 연결시 레코드 삭제 시점 해당 장치의 핸들이 닫혔을 때 CreateIoCompletionPort를 호출하 면 내부적으로 IOCP와 연결된 여러 장 치들을 관리하기 위한 장치 리스트에 새 로운 레코드를 추가한다.
  • 5. 동작 원리 장치와 연결이 끝나면 IO 작업이 완료된 후 완료된 IO에 대한 처리를 수행 할 스레드 풀을 구성한다. 일반적으로 스레드 풀의 크기는 프로세서 개수의 2배 정도를 할당한다(이유는 이후 구조 설명 후 다시 살펴보자). for(int i = 0; i < ioThreadCount; i++) { DWORD ThreadId; HANDLE hThread = (HANDLE)_beginthreadex(NULL,0, workerThread, (LPVOID)i,0,(unsinged int)&dwThreadId); }
  • 6. 동작 원리 IO Completion Queue dwNumberOfBytes Transferred dwCompletionKey lpOverlapped dwError 레코드 추가 시점 I/O 요청이 완료되었을 때 PostQueuedCompletionStatus 함수 호출시 레코드 삭제 시점 IO completion Port가 Wait Thread Queue의 항목을 가져올 때 즉 이 큐는 IOCP와 연결한 device의 IO 작업이 끝났음을 알려주는 큐이다. 방금 전 생성한 스레드 풀에서 적절한 스레드들이 IO Completion Queue 에서 작업거리를 꺼내 IO 완료에 따른 처리를 수행하게 된다.
  • 7. 동작 원리 Waiting Thread Queue(*LIFO) dwThreadId 레코드 추가 시점 GetQueuedCompletionStatus 함수가 호출되었을 때 레코드 삭제 시점 IO Completion Queue가 비어있지 않고 수행 중인 스레드의 개수가 동시 수행 가능한 스레드 개수를 초과하지 않은 경우 이 큐는 IO 작업의 완료를 처리하기 위해 대기하고 있는 스레드들의 큐이다. GetQueuedCompletionStatus 함수를 호출했을 때 당장 IO Completion Queue에 항목이 없거나 동시 수행 가능한 스레드 개수를 초과한 경우 대기 큐에 들어가 대기하고 있다가 적당한 상황이 오면 깨어나서 IO 완료에 대한 처리를 수행하게 된다.
  • 8. 동작 원리 Release Thread List dwThreadId 레코드 추가 시점 IO Completion Port가 Waiting Thread Queue에 있는 스레드를 깨우는 경우 일시정지되었던 스레드가 다시 깨어났을 경우 레코드 삭제 시점 스레드가 다시 GetQueuedCompletionStatus 함수를 호출했을 때 스레드가 정지되는 함수를 호출했을 때 실제 IO 완료에 따른 처리를 수행하기 위해 깨어나서 돌고 있는 Thread 들의 리스트이다. IOCP에서 지정한 개수만큼의 스레드만 이 리스트에 속할 수 있다(그 만큼만 깨어있을 수 있다).
  • 9. 동작 원리 Paused Thread List dwThreadId 레코드 추가 시점 수행 중이던 스레드가 스레드의 정지시키는 함수를 호출했을 때 레코드 삭제 시점 일시정지되었던 스레드가 다시 깨어날 경우 작업을 처리하던 스레드가 특정 함수의 호출(스레드를 블락시키는 함수 등) 했을 때 이 스레드를 Paused Thread List로 보낸다.
  • 10. 예시 장치 리스트 socket 프로세서가 2개인 컴퓨터에서 socket과 연결된 IOCP가 하나 있 다고 가정할 때 IOCP의 동작을 통해 구조를 이해해보자.
  • 11. 예시 장치 리스트 socket 아직 완료된 IO 작업이 없으므로 IO Completion Queue는 비 어있는 상태일 것이다. IO Completion Queue
  • 12. 예시 장치 리스트 socket Waiting Thread Queue에는 처음 생성한 스레드 풀에서 GetQueuedCompletionStatus 함수 호출을 통해 들어간 4개 의 스레드가 대기중인 상황이다. IO Completion Queue Waiting Thread Queue Thread 1 Thread 2 Thread 3 Thread 4
  • 13. 예시 장치 리스트 socket 아직 완료된 IO 작업이 없으니 Release Thread List와 Pause Thread List도 비어있는 상태. IO Completion Queue Waiting Thread Queue Thread 1 Thread 2 Thread 3 Thread 4 Release Thread List Pause Thread List
  • 14. 예시 장치 리스트 socket 이 때 2개의 IO 작업이 완료되었다고 하자. IO Completion Queue Waiting Thread Queue Thread 1 Thread 2 Thread 3 Thread 4 Release Thread List Pause Thread List Completion 1 Completion 2
  • 15. 예시 장치 리스트 socket IO Completion을 처리하기 위해 Waiting Thread Queue 에 가장 최근에 들어온 스레드 2개를 깨우게 된다(Waiting Thread Queue는 성능을 위해 LIFO 순으로 Thread를 꺼낸 다). IO Completion Queue Waiting Thread Queue Thread 1 Thread 2 Thread 3 Thread 4 Release Thread List Pause Thread List Thread 4 Thread 3
  • 16. 예시 장치 리스트 socket Release Thread List에 2개가 돌고 있을 때, 또 다시 새로운 IO 작업이 완료되었다고 하자. 이 때 이미 Relase Thread List에 2 개의 Thread가 돌고 있기 때문에 새로운 스레드는 깨우지 않는 다. IO Completion Queue Waiting Thread Queue Thread 1 Thread 2 Release Thread List Pause Thread List Thread 4 Thread 3 Completion 3 Completion4
  • 17. 예시 장치 리스트 socket 이 때 Thread4에서 어떤 함수가 호출되어 이 Thread가 대기 상 태에 빠지게 된다면 어떻게 될까? IO Completion Queue Waiting Thread Queue Thread 1 Thread 2 Release Thread List Pause Thread List Thread 4 Thread 3 Completion 3 Completion4 Thread 4
  • 18. 예시 장치 리스트 socket IOCP는 항상 스레드 개수를 사용할 수 있는 한 많이 사용하려 고 한다. 그래서 이 경우 1개만 돌고 있으므로 Waiting Thread Queue에서 새로운 스레드를 꺼낸다(이 때문에 프로세서 개수 보다 많은 스레드가 필요한 것이다!). IO Completion Queue Waiting Thread Queue Thread 1 Thread 2 Release Thread List Pause Thread List Thread 3 Completion 4 Thread 4 Thread 2
  • 19. 예시 장치 리스트 socket 그런데 이 상태에서 Pause Thread List의 스레드가 대기 상태 의 작업이 끝난다면? 이 걸 그냥 깨우면 Release Thread List의 최대 Thread 개수를 초과하게 되어버린다. IO Completion Queue Waiting Thread Queue Thread 1 Release Thread List Pause Thread List Thread 3 Completion 4 Thread 4 Thread 2 이제 대기 상태 끝!
  • 20. 예시 장치 리스트 socket 그래서 이 경우 IOCP는 Release Thread List의 스레드가 다시 대기 상태에 들어가기 전까진 스레드를 깨우지 않는다. IO Completion Queue Waiting Thread Queue Thread 1 Release Thread List Pause Thread List Thread 3 Completion 4 Thread 4 Thread 2 불가능!
  • 21. 코드(GQCS/PQCS) 각각의 IO Worker Thread에서는 아래와 같은 코드를 수행해서 IO 완료에 따른 처리를 하게 된다. while(true) { int ret = GetQueuedCompletionStatus(port,&numBytes,&completionKey,&overlapped,TIME_OUT); if(ret == 0 && GetLastError() == WAIT_TIMEOUT) continue; //그 외 경우 에러 처리는 생략. overlapped가 nullptr이라든가 numBytes가 이상하다든가 하는 경우들이 있음. 보통 연결 종료. //completionKey가 종료된 IO작업 종류를 담고 있다고 가정 if(completionKey == IO_RECV) { //recv 관련 작업 수행 } else if(completionKey == IO_SEND) { //send 관련 작업 수행 } } PQCS는 IO Completion Queue에 새 요소를 집어넣을 수 있게 해준다. 다른 스레드에 뭔가 완료 통지를 보내고 싶을 때 유용. 인자는 GQCS와 거의 동일(GQCS 호출시 필요한 데이터 거의 그대로 넘김) //example. 대기중인 다른 스레드 종료시키기(THREAD_RELEASE가 스레드 종료 이벤트라고 가정). PostQueuedCompletionStatus(port, 100, THREAD_RELEASE , overlapped);
  • 22. 코드(SEND/RECV) send, recv를 호출하는 부분에서는 아래와 같은 방식으로 코드를 작성하게 된다. WSARecv(clntSock, //클라이언트 소켓. &ioContext->wsaBuf, //읽을 데이터 버퍼의 포인터. 1, //데이터 입력 버퍼의 개수. nullptr, //recv 결과 읽은 바이트 수. IOCP에서는 비동기 방식으로 사용하지 않으므로 nullptr 넘겨도 무방. &flags, //recv에 사용될 플래그. &ioContext->overlapped), //OVERLAPPED 구조체의 포인터 nullptr); //completion routine 함수의 포인터. IOCP에서는 사용하지 않으므로 nullptr 넘겨도 무방. WSARecv(clntSock, &ioContext->wsaBuf, 1, nullptr, 0, &ioContext->overlapped), nullptr); recv나 send나 거의 똑같다. io 작업을 위한 버퍼와 OVERLAPPED 구조체의 포인터를 넘겨준다.