windows via c/c++ chapter 10

39
Windows via C/C++ - 10 장 장장 장 장장장 장장 I/O - 장장장 [email protected] m

Upload: iluvs

Post on 26-May-2015

1.311 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: Windows via C/C++ Chapter 10
Page 2: Windows via C/C++ Chapter 10
Page 3: Windows via C/C++ Chapter 10

동기 ?! 비동기 ?!

• 동기 (Synchronous) : 동시 발생하는

• 비동기 (Asynchronous) : 동시에 존재하지 않는

Page 4: Windows via C/C++ Chapter 10

01

Page 5: Windows via C/C++ Chapter 10

장치란 ?!

• 정의 : 통신 가능한 어떤 것

• 종류 : 파일 , 직렬포트 , 메일슬롯 , 소켓 , etc... (p.388 표 10-1)

• 특성 : 일부 장치를 제외하고는 인터페이스가 같다 . CreateMailSlot(), CreateNamedPipe()

HANDLE hHandle = CreateFile(...

SetCommConfig (HANDLE hCommDev, ...SetMailslotInfo (HANDLE hMailslot, ...

CloseHandle(HANDLE hObject)

생성

이용

종료

!! 단 장치가 Socket 이였다면 Closesocket(SOCKET s)

Page 6: Windows via C/C++ Chapter 10

HANDLE CreateFile (PCTSTR pszName,DWORD dwDesireAccess,DWORD dwShareMode,PSECURITY_ATTRIBUTES psa,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hFileTemplate);

• pszName : 특정 장치의 인스턴스 / 장치의 타입을 구분• dwDesireAccess : 장치와 데이터 주고받길 원하는 범위• dwShareMode : 장치의 공유특성• Psa : 보안 설정• dwCreationDisposition : 파일을 여는 방법• dwFlagsAndAttributes : 세부적 통신 Flag / 파일의 특성• hFileTemplate : 이미 열린 파일에 대한 핸들 or NULL

!! 파일이 아닌 다른 장치에 대해서는 반드시 OPEN_EXISTING

(p.391 ~ 398)

Page 7: Windows via C/C++ Chapter 10

02

Page 8: Windows via C/C++ Chapter 10

장치 이용하기

• 파일 크기 얻기

• 파일 포인터 위치 지정

• 파일의 끝 설정

BOOL GetFileSize (hFile, ...);

DWORD GetCompressedFileSize (pszFileName, ...);

ReadFile (hFile, ...);

SetFilePointEx (hFile, ... );

SetEndOfFile(hFile, ...);

논리적인 크기 반환

물리적인 크기 반환

64bit 오프셋동기적인 I/O 를 수행할 위치

커널오브젝트의 파일포인터 변경

Page 9: Windows via C/C++ Chapter 10

03

Page 10: Windows via C/C++ Chapter 10

동기 장치 I/O

• 동기 장치 I/O 수행

• 동기 장치 I/O 취소 ( 전적으로 드라이버에 달려있다 .)

BOOL ReadFile (

HANDLE hFile,

PVOID pvBuffer,

DWORD nNumByteToRead,

PDWORD pdwNumBytes,

OVERLAPPED* pOverlapped);

BOOL CancelSynchronousIo (HANDLE hThread);

Page 11: Windows via C/C++ Chapter 10

04

Page 12: Windows via C/C++ Chapter 10

BOOL ReadFile (

HANDLE hFile,

PVOID pvBuffer,

DWORD nNumByteToRead,

PDWORD pdwNumBytes,

OVERLAPPED* pOverlapped); FILE_FLAG_OVERLAPPED

컴퓨터가 수행하는 다른 작업들에 비해 장치 I/O 는 상대적으로

가장 느리고 , 예측할 수 없는 작업 중 하나다 .

비동기 I/O 요청은 고성능의 확장성 있는 애플리케이션을

개발하기 위하여 설계 되었다 .

1. 실제로 I/O 작업을 수행할 장치의 디바이스 드라이버로 전달

2. 디바이스 드라이버가 장치로 부터 응답 대기

3. 애플리케이션은 I/O 완료될때까지 다른 작업 수행

Page 13: Windows via C/C++ Chapter 10

typedef struct _OVERLAPPED {

DWORD Internal;

DWORD InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED, *LPOVERLAPPED;

• Internal : 처리된 I/O 의 에러 코드를 담는데 사용한다 . 비동기 I/O

요청을 시도하면 디바이스 드라이버는 Internal 멤버 값을 STA-

TUS_PENDING 으로 설정하여 아직 작업이 완료되지 않았으며

어떠한 에러도 발생하지 않았음을 나타낸다 .

• InternalHigh : 비동기 I/O 작업이 완료되면 이 멤버는 실제로

송수신된 바이트 수를 저장하게 된다 .

Page 14: Windows via C/C++ Chapter 10

• Offset : 이 인자와 아래 OffsetHigh 를 통해 파일 내에서 I/O

작업을 시작할 위치를 64 비트 오프셋 값으로 지정할 수 있다 .

동일한 파일 커널 오브젝트에 대해 여러 번의 비동기 I/O 요청

시에는 반드시 OVERLAPPED 구조체 내에 I/O 작업을 시작할

위치를 지정해야 한다 .

• OffsetHigh : 위의 Offset 과 같은 역할을 하며 32 비트 상위

파일의 오프셍을 나타낸다 .

• hEvent : 이 멤버는 I/O 완료 통지를 수신하는 네 가지 방법 중

하나의 방법에서 사용된다 . 얼러터블 I/O 통지 방법을 사용하는

경우에는 사용자 임의로 이 멤버를 사용할 수도 있다 .

Page 15: Windows via C/C++ Chapter 10

• 비동기 I/O 요청이 완료되면 I/O 요청 시 사용했던 OVER-

LAPPED 구조체의 주소를 돌려주게 된다 . 그러므로 이

구조체에 장치 핸들이나 유용한 컨텍스트 정보를 저장할 만한

멤버를 포함시켜서 작성하기도 한다 .

Enum IOType

{

OP_RECV,

OP_SEND

}

class OVERLAPPEDEX : public OVERLAPPED

{

IOType m_eIOType;

SOCKET m_hSocket;

};

Page 16: Windows via C/C++ Chapter 10

비동기 장치 I/O 사용 시 주의점

1. 디바이스 드라이버는 비동기 I/O 요청을 항상 선입 선출로 처리 안함

2. 에러 확인을 수행하는 적당한 방법에 대해 알고 있어야 한다 .

1. 비동기 요청에도 시스템에 의해 동기적으로 처리될 때 있다 .

2. Read / Write File 은 I/O 요청이 동기적으로 수행되는 경우 0

이 아닌 값을 반환

3. I/O 요청이 비동기적으로 수행되는 경우나 에러 발생시 FALSE

반환 , 고로 GetLastError (ERROR_IO_PENDING)

3. 데이터 버퍼와 OVERLAPPED 구조체는 I/O 요청이 완료될 때까지

옮겨지거나 삭제되지 않아야 한다 .

Page 17: Windows via C/C++ Chapter 10

요청된 장치 I/O 의 취소

• CancelIo 함수 호출

• 이 함수를 호출한 스레드가 삽입한 모든 I/O 요청 취소

• 장치에 대한 핸들 닫기

• 어떤 스레드가 I/O 요청을 삽입한지 고려하지 않고 모든 I/O 요청

취소

• 핸들이 I/O 컴플레이션 포트와 연계되어 있는 경우를 제외하면 ,

스레드가 종료될 때 종료된 스레드가 삽입하였던 모든 I/O 요청이 취소

• 특정 장치에 대해 하나의 I/O 요청만 취소할 때

• CancelIoEx 함수 호출

Page 18: Windows via C/C++ Chapter 10

05

Page 19: Windows via C/C++ Chapter 10

완료 통지 방법 ?

• 비동기 호출은 언제 완료될 지 알 수 없기때문에 I/O 작업이 완료되면

완료된 사실을 통지해 주어야 한다 .

Page 20: Windows via C/C++ Chapter 10

완료 통지 방법 ?

방법 요약

디바이스 커널 오브젝트 시그널링 • 단일의 장치에 대해 다수의 I/O 요청 적합하지 않다 .

• 특정 스레드가 I/O 요청을 삽입하고 다른 스레드가 완료 통지를 수신할 수 있다 .

이벤트 커널 오브젝트의 시그널링 • 단일의 장치에 대해 다수의 I/O 요청을 수행할 수 있다 .

• 특정 스레드가 I/O 요청을 삽입하고 다른 스레드가 완료 통지를 수신할 수 있다 .

얼러터블 I/O 사용 • 단일의 장치에 대해 다수의 I/O 요청을 수행할 수 있다 .

• 항상 I/O 요청을 삽입한 스레드가 완료 통지를 수신한다 .

I/O 컴플리션 포트 사용 • 단일의 장치에 대해 다수의 I/O 요청을 수행할 수 있다 .

• 특정 스레드가 I/O 요청을 삽입하고 다른 스레드가 완료 통지를 수신할 수 있다 .

• 이 방법이 가장 확장성이 뛰어나고 유연성이 있다 .

Page 21: Windows via C/C++ Chapter 10

디바이스 커널 오브젝트의 시그널링

• 디바이스 커널 오브젝트의 시그널과 논시그널 상태를 이용 .

HANDLE hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...)BYTE bBuffer[100];OVERLAPPED o = { 0 };o.Offset = 345;

BOOL bReadDone = ReadFile(hFile, bBuffer, 100, NULL, &o);DWORD dwError = GetLastError();

If (!bReadDone && (dwError == ERROR_IO_PENDING)) {WaitForSingleObject(hFile, INFINITE);bReadDone = TRUE;

}

If (bReadDone) {...}

Page 22: Windows via C/C++ Chapter 10

디바이스 커널 오브젝트의 시그널링

• 비동기 I/O 를 위해 디바이스를 열 때 반드시

FILE_FLAG_OVERLAPPED

• OVERLAPPED 구조체의 Offset, OffsetHigh, hEvent 초기화

• bReadDone 을 확인후 동기적으로 수행되었는지 확인하고 동기적이

아니라면 비동기적으로 I/O 작업이 요청되었는지 확인

• 읽기 작업 완료 시 bBuffer 에는 읽은 데이터가 , OVERLAPPED

구조체의 Internal 멤버에는 Error 코드가 , InternalHigh 멤버에는

읽은 데이터의 크기가 각각 저장된다 .

Page 23: Windows via C/C++ Chapter 10

디바이스 커널 오브젝트의 시그널링의 문제 ?

HANDLE hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...)BYTE bReadBuffer[100];OVERLAPPED oRead = { 0 };

ReadFile(hFile, bReadBuffer, 100, NULL, &oRead);

BYTE bWriteBuffer[10] = {0, 1, 2, 3, ... };OVERLAPPED oWrite = { 0 };oWrite.Offset = 10;

WirteFile(hFile, bWriteBuffer, _countof(bWriteBuffer), NULL, &oWrite);

...

WaitForSingleObject(hFile, INFINITE)

// ???

Page 24: Windows via C/C++ Chapter 10

이벤트 커널 오브젝트의 시그널링

HANDLE hHandle = CreateFile(..., FILE_FLAG_OVERLAPPED, ...)BYTE bReadBuffer[100];OVERLAPPED oRead = { 0 };oRead.hEvent = CreateEvent(...);

ReadFile(hFile, bReadBuffer, 100, NULL, &oRead);

BYTE bWriteBuffer[10] = {0, 1, 2, 3, ... };OVERLAPPED oWrite = { 0 };oWirte.hEvent = CreateEvent(...);

WirteFile(hFile, bWriteBuffer, _countof(bWriteBuffer), NULL, &oWrite);

Page 25: Windows via C/C++ Chapter 10

이벤트 커널 오브젝트의 시그널링

HANDLE h[2];h[0] = oRead.hEvent;h[1] = oWrite.hEvent;

DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);Switch (dw – WAIT_OBJECT_0) {

case 0: // 읽기 작업 완료break;

case 1: // 쓰기 작업 완료break;

}

GetOverlappedResult(...)

하지만 현재는 Internal 과 InternalHigh 이 문서화

Page 26: Windows via C/C++ Chapter 10

얼러터블 I/O

APC(Asynchronous Procedure Call)

스레드가 생성되면 APC 큐라 불리는 큐가 하나씩 생성

ReadFileEX / WriteFileEX

BOOL ReadFileEx (

HANDLE hFile,

PVOID pvBuffer,

DWORD nNumByteToRead,

OVERLAPPED* pOverlapped,

LPOVERLAPPED_COMPLETION_ROUTINE pfnRoutine);

VOID WINAPI CompletionRoutine (DWORD dwError,DWORD pwNumBytes,OVERLAPPED* po);

Page 27: Windows via C/C++ Chapter 10

얼러터블 I/O

hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);

ReadFileEx(hFile, ...);

WriteFileEx(hFile, ...);

ReadFileEx(hFile, ...);

SomeFunc();

Write I/O Read I/O Read I/O

스레드를 인터럽트 가능한 상태가 되었음을 알려줘야한다 .

즉 , 스레드를 얼러터블 상태로 변경

Page 28: Windows via C/C++ Chapter 10

얼러터블 I/O

얼러터블 상태로 변경할 수 있는 함수

• SleepEx / WaitForSingleObjectEx / WaitForMultipleObjectsEx /

SignalObjectAndWait / GetQueuedCompletionStatusEx / Msg-

WaitForMultipleObjectsEx

얼러터블 I/O 의 장단점

• 장점

• 비동기 호출을 가능하게 만들어준다 .. ㅠ . ㅠ

• 단일 스레드라서 동기화 처리를 할 필요가 없다 . ㅠ . ㅠ

• 단점

• 콜백함수

• 쓰레딩 문제

Page 29: Windows via C/C++ Chapter 10

I/O 컴플리션 포트

• 컨커런트 모델

• 컨커런트 모델을 사용하는 서비스 애플리케이션을 윈도우에서

구현하였을 때 성능이 기대만큼 나오지 않자 개선해서 나온 결과로

태어난 것이 바로 I/O 컴플리션 포트 커널 오브젝트이다

• I/O 컴플리션 포트 생성

HANDLE CreateIoCompletionPort(

HANDLE hFile,

HANDLE hExistingCompletionPort,

ULONG_PTR CompletionKey,

DWORD dwNumberOfConcurrentThreads);

Page 30: Windows via C/C++ Chapter 10

I/O 컴플리션 포트

HANDLE CreateNewCompletionPort (DWORD dwThreads)

{

return CreateIoCompletionPort(

INVALID_HANDLE_VALUE, NULL, 0,

dwThreads);

|

• dwThreads

• 동일 시간에 동시에 수행할 수 있는 스레드의 최대 개수

• 보통은 CPU 개수만큼을 입력

Page 31: Windows via C/C++ Chapter 10

I/O 컴플리션 포트

• I/O 컴플리션 포트 연계

HANDLE CreateIoCompletionPort(

HANDLE hFile,

HANDLE hExistingCompletionPort,

ULONG_PTR CompletionKey,

DWORD dwNumberOfConcurrentThreads);

• hFile : 장치에 대한 핸들 ( 파일 , 소켓 , 메일슬롯 , 파이프등 )

• hExistingCompletionPort : 생성해 둔 I/O 컴플리션 포트 핸들

• CompletionKey : 컴플리션 키 ( 사용자가 임의로 결정할 수 있다 .)

Page 32: Windows via C/C++ Chapter 10

I/O 컴플리션 포트

• I/O 컴플리션 포트 연계

BOOL AssociateDeviceWithCompletionPort(

HANDLE hDevice,

HANDLE hExistingCompletionPort,

ULONG_PTR CompletionKey,) {

HANDLE h = CreateIoCompletionPort(hDevice,

hCompletionPort, dwCompletionKey, 0);

return (h == hCompletionPort);

}

Page 33: Windows via C/C++ Chapter 10

I/O 컴플리션 포트

• 장치 리스트

• I/O 컴플리션 큐

• 대기 스레드 큐

• 릴리즈 스레드 리스트

• 일시 정지 스레드 리스트

Page 34: Windows via C/C++ Chapter 10

I/O 컴플리션 포트

Device List I/O Request ListI/O Completion

Queue

커널 모드

CreateCompletionPort

WSARecv()WSASend()

ReadFileEX()…

GetQueuedComple-tionStatus()

유저 모드

Page 35: Windows via C/C++ Chapter 10

I/O 컴플리션 포트를 이용한 아키텍쳐 설계

• 클라이언트의 요청을 처리하는 스레드 풀

• 풀 내에 몇 개의 스레드를 생성해 두는 것이 좋은가 ? ( 다음발표자

분 )

• 완료 통지가 전달 되었을 때 처리할 수 있도록 스레드를 대기 상태로 !!BOOL GetQueuedCompletionStatus(

HANDLE hCompletionPort,

PDWORD pdwNumberOfBytesTransferred,

PULONG_PTR pCompletionKey,

OVERLAPPED** ppOverlapped,

DWORD dwMilliseconds);

Page 36: Windows via C/C++ Chapter 10

I/O 컴플리션 포트를 이용한 아키텍쳐 설계

• 대기 스레드 큐

• 후입선출 (LIFO) 방식으로 스레드를 깨운다 .

• 릴리즈 스레드 리스트

• I/O 컴플리션 포트가 대기 스레드 큐에 있는 스레드를 깨우는 경우

• 일시 정지되었던 스레드가 다시 깨어났을 경우

• 일시 정지 스레드 리스트

• 수행 중이던 스레드가 스레드를 정지시키는 함수를 호출

• 정지 중이던 스레드가 깨어나면 릴리즈 스레드 리스트로 삽입

Page 37: Windows via C/C++ Chapter 10

I/O 컴플리션 포트의 스레드 풀 관리방법

• I/O 컴플리션 포트 생성할 때 지정한 스레드 개수 이상을 초과할 수 없다

• 근데 왜 ?! 이보다 많은 스레드를 풀로 관리해야 하는가 ?

• 릴리즈 스레드 리스트

• 대기 스레드 리스트

I/O 컴플리션 사용 목적

CPU 가 계속해서 작업을 수행하도록 상태를 유지하는 것

Page 38: Windows via C/C++ Chapter 10
Page 39: Windows via C/C++ Chapter 10