异步重叠IO的实现原理
原理图:
重叠IO实现异步,主要是利用重叠的命名,加上事件的同同步
在使用重叠I/O时,线程需要创建OVERLAPPED结构以供I/O处理。该结构中最重要的成员是hEvent,它是作为一个同步对象而存在,如果hEvent为NULL,那么此时的同步对象即为文件句柄、管道句柄等I/O操作对象。当I/O完成后,会使这里的同步对象受信,从而通知用户线程。
WaitForMuliteSingleObject 来等待事件,接受到事件消息后,利用GetOverlappedRequest 来获取IO执行的结果
这里有一个关键,不用的IO处理,利用不同的事件EVENT才区分,不然就会混乱,没有办法进行区分:
例:
DWORD dwRead;
BYTE bBuf1[BUF_SIZE], bBuf2[BUF_SIZE], bBuf3[BUF_SIZE];
OVERLAPPED ov1 = { 0, 0, 0, 0, NULL };
OVERLAPPED ov2 = { 0, 0, 0, 0, NULL };
OVERLAPPED ov3 = { 0, 0, 0, 0, NULL };
HANDLE hFile = Create(…., FILE_FLAG_OVERAPPED,….., );
ReadFiele( hFile, bBuf1, sizoef(bBuf1), &dwRead, &ov1 );
ReadFiele( hFile, bBuf2, sizoef(bBuf2), &dwRead, &ov2 );
ReadFiele( hFile, bBuf3, sizoef(bBuf3), &dwRead, &ov3 );
GetOverappedRequest( hFile, &ov1, &dwRead, TRUE );
这里对于hFile有三个重叠的I/O操作,但他们的同步对象却都为hFile。使用GetOverlappedResult进行等待操作,这里看似在等待第一个I/O处理的完成,其实只要有任何一个I/O处理完成,该函数就会返回,相当于忽略了其他两个I/O操作的结果
其实,这里有一个很重要的原则:对于一个重叠句柄上有多于一个I/O操作的时候,应该使用事件对象而不是文件句柄来实现同步。
正确示例:
DWORD dwRead;
BYTE bBuf1[BUF_SIZE], bBuf2[BUF_SIZE], bBuf3[BUF_SIZE];
HANDLE hEvent1 = CreateEvent( NULL, Fallse, False, NULL );
HANDLE hEvent2 = CreateEvent( NULL, Fallse, False, NULL );
HANDLE hEvent3 = CreateEvent( NULL, Fallse, False, NULL );
OVERLAPPED ov1 = { 0, 0, 0, 0, hEvent1 };
OVERLAPPED ov2 = { 0, 0, 0, 0, hEvent2 };
OVERLAPPED ov3 = { 0, 0, 0, 0, hEvent3 };
HANDLE hFile = Create(…., FILE_FLAG_OVERAPPED,….., );
ReadFiele( hFile, bBuf1, sizoef(bBuf1), &dwRead, &ov1 );
ReadFiele( hFile, bBuf2, sizoef(bBuf2), &dwRead, &ov2 );
ReadFiele( hFile, bBuf3, sizoef(bBuf3), &dwRead, &ov3 );
GetOverappedRequest( hFile, &ov1, &dwRead, TRUE );
到这里异步重叠IO的原理基本都已经熟悉了吧,实现异步IO的方法分为3类,重叠IO是第一种,还有,异步过程调用(APC)扩展IO、完成端口(IOCP),将在对其进行进一步阐述。(在实现socket完成端口模型的同时推出)