关于GetOverlappedResult函数的一些知识

来源:互联网 发布:淘宝改价新规则 编辑:程序博客网 时间:2024/04/30 18:22

之前在写重叠I\O的代码的时候,记得那时是从网络上拷贝的代码例子。在关于重叠操作的等待结果时,一般都是如下的过程:

  调用waitformultipleobject或waitforsingleobject函数来等待某一个I\O请求绑定的事件对象的激活。等到激活事件对象后,再调用GetOverlappedResult函数取得重叠I\O的结果,这里GetOverlappedResult的返回值一般都是TRUE(即重叠操作成功)。

代码如下:

rc = ReadFile(hFile,buf,300,&numread,&overlap);//因为是overlapped操作,ReadFile会将读文件请求放入读队列之后立即返回(false),//而不会等到文件读完才返回(true)if (rc){//文件真是被读完了,rc为true// 或当数据被放入cache中,或操作系统认为它可以很快速地取得数据,rc为true}else{if (GetLastError() == ERROR_IO_PENDING){//当错误是ERROR_IO_PENDING,那意味着读文件的操作还在进行中//等候,直到文件读完WaitForSingleObject(hFile, INFINITE);rc = GetOverlappedResult(hFile,&overlap,&numread,FALSE);//上面二条语句完成的功能与下面一条语句的功能等价:// GetOverlappedResult(hFile,&overlap,&numread,TRUE);}else{//出错了}}CloseHandle(hFile);

如果这样做也可以,不用关心一些关于getoverlappedresult函数的细节。


现在深入研究下getoverlappedresult函数的细节:

BOOL
WINAPI
GetOverlappedResult(
    HANDLE hFile,
    LPOVERLAPPED lpOverlapped,
    LPDWORD lpNumberOfBytesTransferred,
    BOOL bWait
    )

下面是OVERLAPPED的结构定义:
typedef struct _OVERLAPPED { 
    DWORD  Internal; 
    DWORD  InternalHigh; 
    DWORD  Offset; 
    DWORD  OffsetHigh; 
    HANDLE hEvent; 
} OVERLAPPED; 


其函数实现的伪代码为:

{
    DWORD WaitReturn;


    //
    // Did caller specify an event to the original operation or was the
    // default (file handle) used?
    //


    if (lpOverlapped->Internal == (DWORD)STATUS_PENDING ) {
        if ( bWait ) {
            //
            //现在还是PENDING,且还需要等待,则无限期等待。
            //很多人会自己调用WaitForSingleObject后再调用GetOverlappedResult,其实看起来
            //没多少必要。
            //
            WaitReturn = WaitForSingleObject(
                            ( lpOverlapped->hEvent != NULL ) ?
                                lpOverlapped->hEvent : hFile,
                            INFINITE
                            );
            }
        else {
            WaitReturn = WAIT_TIMEOUT;
            }


        if ( WaitReturn == WAIT_TIMEOUT ) {
            //  !bWait and event in not signalled state
            SetLastError( ERROR_IO_INCOMPLETE );
            return FALSE;
            }


        if ( WaitReturn != 0 ) {
             return FALSE;    // WaitForSingleObject calls BaseSetLastError
             }
        }


    *lpNumberOfBytesTransferred = (DWORD)lpOverlapped->InternalHigh;


    if ( NT_SUCCESS((NTSTATUS)lpOverlapped->Internal) ){
        return TRUE;
        }
    else {
        BaseSetLastNTError( (NTSTATUS)lpOverlapped->Internal );
        return FALSE;
        }
}


由上面代码可以看出,Internal成员就是用来存储已经处理的I\O请求的状态码。InternalHigh成员是在I\O请求完成后,实际传输的字节数,如果没有完成,则这个成员值应该被忽略。

WaitForSingleObject(hFile, INFINITE);rc = GetOverlappedResult(hFile,&overlap,&numread,FALSE);
一般情况下waitsingle的第二个参数为INFINITE的话,除非出现什么其他I\O错误,要不然等wait到事件对象后,I\O操作都是已经成功完成了的。那么再调用Getoverlappedresult函数就会直接返回TRUE了。

如果把waitsingle的第二个参数为某个超时时间值时,那么Getoverlappedresult函数的最后一个blwait参数最好设置为TRUE,这样的话才能保证Getoverlappedresult返回TRUE,要不然就会返回FALSE,而此时的GetLastError返回值就是ERROR_IO_INCOMPLETE 了,代表I\O操作还未完成。


或者是直接用Getoverlappedresult(hFile, &overlap, &numread, TRUE);这一句来完成上面两句的任务,效果一样。不过好像大家都是用的上面两句。

0 0
原创粉丝点击