만일, read -> cpu 사용 코드 -> write -> cpu 사용 코드 -> read -> cpu 사용 코드 -> write 와 같이 반복되는 작업인 경우, 각 과정이 1초가 사용된다면, 위 과정은 일반적인 i/o 함수 사용시 총 7초가 사용됩니다. 허나, non-blocked, asynchronous, iocp, 혹은 overlapped i/o를 사용한다면, i/o 함수는 즉각적으로 리턴이 되어, 이후의 코드를 진행할 수 있습니다. 그렇다면, 위 과정은 운이 좋다면 총 3초(cpu 사용코드만 지체됨), 일반적으로는 4초(i/o와 cpu 사용코드가 동시 실행하여 1초가 걸린다고 가정)로 가정할 수 있습니다.
말로 이해하기 어렵다면, 아래 msdn에서 알려준 그림을 참고하세요. (출처 : msdn)
즉, cpu 사용(User mode)과 i/o를 동시에 진행할 수 있다는 장점이 있습니다.
이러한 overlapped i/o를 사용할 때 주의할 점은,
- GetOverlappedResult를 통해 Overlapped i/o의 수행 결과를 체크해야 한다.
- File Pointer를 수동으로 설정해야 한다.
; 일반적인 block i/o는 i/o 함수 호출후 File Pointer가 자동으로 뒤로 넘어가는데, overlapped i/o는 수동으로 함수 호출전에 설정해야 함 - OVERLAPPED 구조체의 event를 사용자가 생성한다면, auto-reset으로 하기를 추천한다.
- ReadFile / WriteFile 사용시, 쓰기 버퍼의 크기와 File Pointer 위치는 sector 크기의 배수여야 한다. 일반적으로 512byte이며, 4096byte도 있다.
- FILE_FLAG_NO_BUFFERING를 가지고 CreateFile된 경우, ReadFile / WriteFile 사용시, File Pointer 위치와 쓰려는 버퍼 크기는 disk의 sector 단위, 즉, 일반적으로 512byte(혹은 4096byte) 정수배가 되어야 한다. 그렇지 않는 경우, 87(=ERROR_INVALID_PARAMETER)오류가 발생한다.
- EOF 혹은 그 이후의 위치를 ReadFile하면 I/O Pending은 발생하나, Overlapped Result가 ERROR_HANDLE_EOF가 전달된다.
와 같습니다.
Overlapped i/o 사용시의 주요한 tip은 다음과 같습니다.
1. File pointer 계산시에는 LARGE_INTEGER를 활용하면 편리합니다.
2. I/O completion, 즉 I/O 완료때 까지 기다릴 때, MsgWaitForMultipleObjects를 호출하면, UI가 깨지지 않게 할 수 있습니다. 다시말해, 만일, MFC의 OnButton등에서 100MB의 파일을 읽는다고 하면, I/O 함수에 의해 Primary thread가 wait되기 때문에 UI Message Pumping이 발생하지 않아 화면이 깨지게 됩니다. 그래서 보통 I/O Thread를 만들어서 해당 함수를 수행하게 되는데, 그러다 보면 Thread 관리라는 어렵고 귀찮은 문제가 발생합니다. 이와 대조적으로, overlapped i/o로 Read한뒤, MsgWaitForMultipleObjects를 호출하여 완료때 까지 기다리면, Message Pumping이 수행되어 UI가 깨지지 않게 됩니다.
3. OVERLAPPED의 hEvent를 RegisterWaitForSingleObject와 연결하면, I/O가 완료될때 OS가 관리하는 thread pool에서 사용자가 등록한 callback 함수를 호출 받을 수 있습니다. 이는 File 관련 I/O외에도 Network 관련 I/O에서 잘 활용하면 매우 편리하게 사용할 수 있습니다. 보통 경험상 WT_EXECUTELONGFUNCTION 옵션이 가장 적합했습니다.
4. Overlapped i/o를 사용한다면, CreateFile에서 FILE_FLAG_NO_BUFFERING을 조합하면 최적화된 성능을 가질 수 있다고 합니다. 다만, 해당 경우에는, 앞서 설명한 sector 크기의 배수 조건을 만족해야 합니다.
아래는 Overlapped i/o로 이뤄지는 ReadFile, WriteFile 호출 예제 입니다.
// overlapped_write.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> |
위 코그를 실행하면 다음과 같습니다.
2048 bytes written. Readed : bcdefghijk Readed : tuvwx, Byte Transfered : 5 Read Seek at 2048, ERROR_HANDLE_EOF returned, Byte Transfered : 0 계속하려면 아무 키나 누르십시오 . . . |
'프로그래밍 > Win32 Deep Inside' 카테고리의 다른 글
Heap에 대해... (process default heap, private heap, fragmentation) (0) | 2014.10.10 |
---|---|
지연된 DLL 로드(delay load dll) (2) | 2014.05.07 |
Zombie Thread 오류로 인한 unknown/unloaded 오류 발견 & 대처법 (0) | 2010.10.20 |
열린 파일 찾기 (UnLocker) 소스 공유 (2) | 2010.08.23 |
DLL을 만들때의 최고의 습관 (DLLMain deadlock 회피) - (1) (1) | 2009.10.01 |