5. 장치란 ?!
• 정의 : 통신 가능한 어떤 것
• 종류 : 파일, 직렬포트, 메일슬롯, 소켓, etc... (p.388 표 10-1)
• 특성 : 일부 장치를 제외하고는 인터페이스가 같다.
CreateMailSlot(), CreateNamedPipe()
HANDLE hHandle = CreateFile(... 생성
SetCommConfig (HANDLE hCommDev, ...
SetMailslotInfo (HANDLE hMailslot, ... 이용
CloseHandle(HANDLE hObject) 종료
!! 단 장치가 Socket이였다면 Closesocket(SOCKET s)
6. 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)
7.
8. 장치 이용하기
• 파일 크기 얻기
• 파일 포인터 위치 지정
• 파일의 끝 설정
BOOL GetFileSize (hFile, ...); 논리적인 크기 반환
DWORD GetCompressedFileSize (pszFileName, ...);
물리적인 크기 반환
ReadFile (hFile, ...); 64bit 오프셋
SetFilePointEx (hFile, ... ); 동기적인 I/O를 수행할 위치
SetEndOfFile(hFile, ...); 커널오브젝트의 파일
포인터 변경
9.
10. 동기 장치 I/O
• 동기 장치 I/O 수행
• 동기 장치 I/O 취소 (전적으로 드라이버에 달려있다.)
BOOL ReadFile (
HANDLE hFile,
PVOID pvBuffer,
DWORD nNumByteToRead,
PDWORD pdwNumBytes,
OVERLAPPED* pOverlapped);
BOOL CancelSynchronousIo (HANDLE hThread);
11.
12. 컴퓨터가 수행하는 다른 작업들에 비해 장치 I/O는 상대적으로 가
장 느리고, 예측할 수 없는 작업 중 하나다.
비동기 I/O 요청은 고성능의 확장성 있는 애플리케이션을 개발하
기 위하여 설계 되었다.
1. 실제로 I/O 작업을 수행할 장치의 디바이스 드라이버로 전달
2. 디바이스 드라이버가 장치로 부터 응답 대기
3. 애플리케이션은 I/O 완료될때까지 다른 작업 수행
BOOL ReadFile (
HANDLE hFile,
PVOID pvBuffer,
DWORD nNumByteToRead,
PDWORD pdwNumBytes,
OVERLAPPED* pOverlapped); FILE_FLAG_OVERLAPPED
13. typedef struct _OVERLAPPED {
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;
• Internal : 처리된 I/O의 에러 코드를 담는데 사용한다. 비동기 I/O 요청
을 시도하면 디바이스 드라이버는 Internal 멤버 값을
STATUS_PENDING으로 설정하여 아직 작업이 완료되지 않았으며
어떠한 에러도 발생하지 않았음을 나타낸다.
• InternalHigh : 비동기 I/O 작업이 완료되면 이 멤버는 실제로 송수신된
바이트 수를 저장하게 된다.
14. • Offset : 이 인자와 아래 OffsetHigh를 통해 파일 내에서 I/O 작업을 시
작할 위치를 64비트 오프셋 값으로 지정할 수 있다. 동일한 파일 커널
오브젝트에 대해 여러 번의 비동기 I/O 요청 시에는 반드시
OVERLAPPED 구조체 내에 I/O 작업을 시작할 위치를 지정해야 한다.
• OffsetHigh : 위의 Offset과 같은 역할을 하며 32비트 상위 파일의 오
프셍을 나타낸다.
• hEvent : 이 멤버는 I/O 완료 통지를 수신하는 네 가지 방법 중 하나의
방법에서 사용된다. 얼러터블 I/O 통지 방법을 사용하는 경우에는 사
용자 임의로 이 멤버를 사용할 수도 있다.
15. • 비동기 I/O 요청이 완료되면 I/O 요청 시 사용했던
OVERLAPPED 구조체의 주소를 돌려주게 된다. 그러므로 이
구조체에 장치 핸들이나 유용한 컨텍스트 정보를 저장할 만한
멤버를 포함시켜서 작성하기도 한다.
Enum IOType
{
OP_RECV,
OP_SEND
}
class OVERLAPPEDEX : public OVERLAPPED
{
IOType m_eIOType;
SOCKET m_hSocket;
};
16. 비동기 장치 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 요청이 완료될 때까지
옮겨지거나 삭제되지 않아야 한다.
17. 요청된 장치 I/O의 취소
• CancelIo 함수 호출
• 이 함수를 호출한 스레드가 삽입한 모든 I/O 요청 취소
• 장치에 대한 핸들 닫기
• 어떤 스레드가 I/O 요청을 삽입한지 고려하지 않고 모든 I/O 요청 취소
• 핸들이 I/O 컴플레이션 포트와 연계되어 있는 경우를 제외하면, 스레드가
종료될 때 종료된 스레드가 삽입하였던 모든 I/O 요청이 취소
• 특정 장치에 대해 하나의 I/O 요청만 취소할 때
• CancelIoEx 함수 호출
18.
19. 완료 통지 방법?
• 비동기 호출은 언제 완료될 지 알 수 없기때문에 I/O 작업이 완료되면 완료
된 사실을 통지해 주어야 한다.
20. 완료 통지 방법?
방법 요약
디바이스 커널 오브젝트 시그널링 • 단일의 장치에 대해 다수의 I/O 요청 적합하지
않다.
• 특정 스레드가 I/O 요청을 삽입하고 다른 스레
드가 완료 통지를 수신할 수 있다.
이벤트 커널 오브젝트의 시그널링 • 단일의 장치에 대해 다수의 I/O 요청을 수행할
수 있다.
• 특정 스레드가 I/O 요청을 삽입하고 다른 스레
드가 완료 통지를 수신할 수 있다.
얼러터블 I/O 사용 • 단일의 장치에 대해 다수의 I/O 요청을 수행할
수 있다.
• 항상 I/O 요청을 삽입한 스레드가 완료 통지를
수신한다.
I/O 컴플리션 포트 사용 • 단일의 장치에 대해 다수의 I/O 요청을 수행할
수 있다.
• 특정 스레드가 I/O 요청을 삽입하고 다른 스레
드가 완료 통지를 수신할 수 있다.
• 이 방법이 가장 확장성이 뛰어나고 유연성이 있
다.
22. 디바이스 커널 오브젝트의 시그널링
• 비동기 I/O를 위해 디바이스를 열 때 반드시 FILE_FLAG_OVERLAPPED
• OVERLAPPED 구조체의 Offset, OffsetHigh, hEvent 초기화
• bReadDone을 확인후 동기적으로 수행되었는지 확인하고 동기적이 아니
라면 비동기적으로 I/O 작업이 요청되었는지 확인
• 읽기 작업 완료 시 bBuffer에는 읽은 데이터가, OVERLAPPED 구조체의
Internal 멤버에는 Error코드가, InternalHigh 멤버에는 읽은 데이터의 크기
가 각각 저장된다.
27. 얼러터블 I/O
hFile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);
ReadFileEx(hFile, ...);
WriteFileEx(hFile, ...);
ReadFileEx(hFile, ...);
SomeFunc();
Write I/O Read I/O Read I/O
스레드를 인터럽트 가능한 상태가 되었음을 알려줘야한다.
즉, 스레드를 얼러터블 상태로 변경
28. 얼러터블 I/O
얼러터블 상태로 변경할 수 있는 함수
• SleepEx / WaitForSingleObjectEx / WaitForMultipleObjectsEx /
SignalObjectAndWait / GetQueuedCompletionStatusEx /
MsgWaitForMultipleObjectsEx
얼러터블 I/O의 장단점
• 장점
• 비동기 호출을 가능하게 만들어준다..ㅠ.ㅠ
• 단일 스레드라서 동기화 처리를 할 필요가 없다. ㅠ.ㅠ
• 단점
• 콜백함수
• 쓰레딩 문제
29. I/O 컴플리션 포트
• 컨커런트 모델
• 컨커런트 모델을 사용하는 서비스 애플리케이션을 윈도우에서 구현
하였을 때 성능이 기대만큼 나오지 않자 개선해서 나온 결과로 태어난
것이 바로 I/O 컴플리션 포트 커널 오브젝트이다
• I/O 컴플리션 포트 생성
HANDLE CreateIoCompletionPort(
HANDLE hFile,
HANDLE hExistingCompletionPort,
ULONG_PTR CompletionKey,
DWORD dwNumberOfConcurrentThreads);
30. I/O 컴플리션 포트
HANDLE CreateNewCompletionPort (DWORD dwThreads)
{
return CreateIoCompletionPort(
INVALID_HANDLE_VALUE, NULL, 0,
dwThreads);
|
• dwThreads
• 동일 시간에 동시에 수행할 수 있는 스레드의 최대 개수
• 보통은 CPU 개수만큼을 입력
31. I/O 컴플리션 포트
• I/O 컴플리션 포트 연계
HANDLE CreateIoCompletionPort(
HANDLE hFile,
HANDLE hExistingCompletionPort,
ULONG_PTR CompletionKey,
DWORD dwNumberOfConcurrentThreads);
• hFile : 장치에 대한 핸들 (파일, 소켓, 메일슬롯, 파이프등)
• hExistingCompletionPort : 생성해 둔 I/O 컴플리션 포트 핸들
• CompletionKey : 컴플리션 키 (사용자가 임의로 결정할 수 있다.)
32. I/O 컴플리션 포트
• I/O 컴플리션 포트 연계
BOOL AssociateDeviceWithCompletionPort(
HANDLE hDevice,
HANDLE hExistingCompletionPort,
ULONG_PTR CompletionKey,) {
HANDLE h = CreateIoCompletionPort(hDevice,
hCompletionPort, dwCompletionKey, 0);
return (h == hCompletionPort);
}
33. I/O 컴플리션 포트
• 장치 리스트
• I/O 컴플리션 큐
• 대기 스레드 큐
• 릴리즈 스레드 리스트
• 일시 정지 스레드 리스트
34. I/O 컴플리션 포트
커널 모드
Device List I/O Request List I/O Completion Queue
유저 모드
WSARecv()
WSASend() GetQueuedCompletionS
CreateCompletionPort
ReadFileEX() tatus()
…
35. I/O 컴플리션 포트를 이용한 아키텍쳐 설계
• 클라이언트의 요청을 처리하는 스레드 풀
• 풀 내에 몇 개의 스레드를 생성해 두는 것이 좋은가? (다음발표자분)
• 완료 통지가 전달 되었을 때 처리할 수 있도록 스레드를 대기 상태로!!
BOOL GetQueuedCompletionStatus(
HANDLE hCompletionPort,
PDWORD pdwNumberOfBytesTransferred,
PULONG_PTR pCompletionKey,
OVERLAPPED** ppOverlapped,
DWORD dwMilliseconds);
36. I/O 컴플리션 포트를 이용한 아키텍쳐 설계
• 대기 스레드 큐
• 후입선출(LIFO) 방식으로 스레드를 깨운다.
• 릴리즈 스레드 리스트
• I/O 컴플리션 포트가 대기 스레드 큐에 있는 스레드를 깨우는 경우
• 일시 정지되었던 스레드가 다시 깨어났을 경우
• 일시 정지 스레드 리스트
• 수행 중이던 스레드가 스레드를 정지시키는 함수를 호출
• 정지 중이던 스레드가 깨어나면 릴리즈 스레드 리스트로 삽입
37. I/O 컴플리션 포트의 스레드 풀 관리방법
• I/O 컴플리션 포트 생성할 때 지정한 스레드 개수 이상을 초과할 수 없다
• 근데 왜?! 이보다 많은 스레드를 풀로 관리해야 하는가?
• 릴리즈 스레드 리스트
• 대기 스레드 리스트
I/O 컴플리션 사용 목적
CPU가 계속해서 작업을 수행하도록 상태를 유지하는 것