비동기 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