비동기 IO 사용방법
방법1) ReadFile(), WriteFile() 사용
CreateFile()시 FILE_FLAG_OVERLAPPED 사용.
ReadFile(), WriteFile()와 overlapped 구조체 사용하며 event가 필요함.
GetOverlappedResult()로 통지를 받음.
동기IO는 file pointer로 읽고 쓰며 비동기IO는 지정한 OVERLAPPED 구조체로 읽고 쓴다.
SetFilePointer() 같은 file pointer 조작 API는 사용할 수 없음.
방법2) ReadFilexEx(), WriteFileEx() 사용
ReadFilexEx(), WriteFileEx() 비동기 전용 API.
인자에 실제 읽은 bytes가 없고 LPOVERLAPPED_COMPLETION_ROUTINE(완료 통지 함수) 인자가 있다.
completion routine을 위해 OS는 APC를 이용한다.
**.APC(Asynchronouse Procedure Call)
: 어플리케이션 실행과 비동기적 함수 실행을 OS에 요청하는 구조를 갖음.
thread마다 APC queue를 갖고 있으며 커널 모드 APC, 유저 모드 APC가 있다.
completion routine 함수 원형(prototype) : FileIOCompletionRoutine Callback Function
VOID CALLBACK FileIOCompletionRoutine(
[in] DWORD dwErrorCode, //에러코드
[in] DWORD dwNumberOfBytesTransfered, //전송된 bytes
[in] LPOVERLAPPED lpOverlapped //overlapped 구조체 포인터
);
경계 가능 상태 : thread가 특정 상태가 아니면 실행되지 않는 유저모드 APC의 상태를 의미
경계 가능 대기 API : 경계 가능 상태 스레드를 만들기 위해 사용하는 API
MsgWaitForMultipleObjectEx(), WaitForSingleObjectEx(), WaitForMultipleObjectsEx(), SleepEx()
샘플 : 방법1) ReadFile() 사용 파일 읽기
#include <windows.h>
#include <tchar.h>
#include <iostream>
char buf[20000000];
int main(void)
{
ZeroMemory(buf, sizeof(buf));
HANDLE hEvent = NULL;
HANDLE hFile = NULL;
try
{
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
//비동기용으로 File 열기
hFile = CreateFile(_T("D:\\BigFile.dat"), GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
throw _T("failed CreateFile");
OVERLAPPED ol;
ol.hEvent = hEvent;
ol.Offset = 0;
ol.OffsetHigh = 0;
DWORD xferCnt = 0;
//비동기 파일 읽기 (overlapped 사용)
BOOL ret = ReadFile(hFile, buf, sizeof(buf), &xferCnt, &ol);
if (ret > 0) //ReadFile() 완료된 경우 : 용량이 작은 파일이면 즉시 끝남
throw _T("complete ReadFile()");
if (ret == 0 && GetLastError() != ERROR_IO_PENDING) //ReadFile() 실패인 경우
throw _T("failed async IO start");
int cnt = 0;
while (!GetOverlappedResult(hFile, &ol, &xferCnt, FALSE))
{
if (GetLastError() != ERROR_IO_INCOMPLETE) //GetOverlappedResult() 실패
throw _T("failed GetOverlappedResult()");
_tprintf(_T("read aysnc IO : %d th, readed bytes : %0ld\n"), ++cnt, xferCnt); //xferCnt는 완료전까지 0임
Sleep(1000);
}
//정상 완료인 경우
_tprintf(_T("complete ReadFile() async IO \n"));
_tprintf(_T("read bytes : %0ld\n"), xferCnt);
}
catch (TCHAR* errmsg)
{
_tprintf(errmsg);
_tprintf(_T("\n"));
if (hFile != NULL) CloseHandle(hFile);
if (hEvent != NULL) CloseHandle(hEvent);
}
return 0;
}
샘플 : 방법2) ReadFilexEx() 사용 파일 읽기
#include <windows.h>
#include <tchar.h>
#include <iostream>
char buf[0000000];
VOID CALLBACK FileIOCompletionRoutine(DWORD dwErrorCode, DWORD dwNumberOfBytesTransfered, LPOVERLAPPED lpOverlapped)
{ //에러코드, 전송된 bytes, overlapped 구조체 포인터
_tprintf(_T("complete async IO\n"));
_tprintf(_T(" read bytes : %0ld\n"), dwNumberOfBytesTransfered);
_tprintf(_T(" passive param : %ld\n"), lpOverlapped->hEvent);
}
int main(void)
{
ZeroMemory(buf, sizeof(buf));
HANDLE hFile = NULL;
try
{
//비동기용으로 File 열기
hFile = CreateFile(_T("D:\\BigFile.dat"), GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
throw _T("failed CreateFile");
OVERLAPPED ol;
ol.hEvent = (HANDLE)777; //전달할 임의 값
ol.Offset = 0;
ol.OffsetHigh = 0;
//비동기 파일 읽기 (비동기 IO 전용 API 사용)
BOOL ret = ReadFileEx(hFile, buf, sizeof(buf), &ol, FileIOCompletionRoutine);
if (ret <= 0)
throw _T("failed ReadFileEx() : async IO");
//ReadFileEx() 성공인 경우
int cnt = 0;
do
{
_tprintf(_T("async IO waiting : %ld th\n"), ++cnt);
} while(SleepEx(1000, TRUE) != WAIT_IO_COMPLETION);
/*
위에서 SleepEx() 대신 WaitForSingleObjectEx() 사용하면
async IO 완료시 시그널 상태가 되어
경계 가능 상태가 아니므로 completion routine이 실행되지 않는다.
*/
}
catch (TCHAR* errmsg)
{
_tprintf(errmsg);
_tprintf(_T("\n"));
if (hFile != NULL) CloseHandle(hFile);
}
return 0;
}
'C++' 카테고리의 다른 글
MFC tip (0) | 2011.01.25 |
---|---|
OLEDB (0) | 2011.01.24 |
COM (0) | 2011.01.24 |
MFC 기초 정리 (0) | 2011.01.21 |
SEH (Structured Exception Handling) 예외처리 (0) | 2011.01.12 |
윈도우 GUI에서 콘솔(console) 띄우기 (0) | 2011.01.11 |
Windows 접근 제어 (0) | 2011.01.11 |
CRITICAL_SECTION을 사용한 Lock 클래스 예제 (0) | 2011.01.07 |