zoukankan      html  css  js  c++  java
  • 第6章 Overlapped I/O, 在你身后变戏法 ---被激发的 File Handles -3

        最简单的 overlapped I/O 类型,是使用它自己的文件 handle 作为同步机制。首先你以 FILE_FLAG_OVERLAPPED 告诉 Win32 说你不要使用默认的同步 I/O。然后,你设立一个 OVERLAPPED 结构,其中内含“I/O 请求”的所有必要参数,并以此识别这个“I/O 请求”,直到它完成为止。接下来,调用 ReadFile() 并以 OVERLAPPED 结构的地址作为最后一个参数。这时候,理论上,Win32 会在后台处理你的请求。你的程序可以放心地继续处理其他事情。

        如果你需要等待 overlapped I/O 的执行结果, 作为WaitForMultipleObjects() 的一部分, 请在 handle 数组中加上这个文件handle。文件 handle 是一个核心对象,一旦操作完毕即被激发。当你完成操作之后,请调用 GetOverlappedResult() 以确定结果如何。
        
        调用 GetOverlappedResult() , 你获得的结果和“ 调用 ReadFile() 或WriteFile() 而没有指定 overlapped I/O”所传回的东西一样。这个函数的价值在于,在文件操作真正完成之前,你不可能确实知道它是否成功。甚至在一个完美无瑕的环境下读一个已知的磁盘文件,也有可能发生硬件错误、服务器当掉,或任何未能预期的错误。因此,调用 GetOverlappedResult() 是很重要的。
        
            GetOverlappedResult() 规格如下:
        
        BOOL GetOverlappedResult(
            HANDLE hFile,
            LPOVERLAPPED lpOverlapped,
            LPDWORD lpNumberOfBytesTransferred,
            BOOL bWait
        );
        参数
        hFile                 文件或设备(device)的 handle。
        lpOverlapped             一个指针,指向 OVERLAPPED 结构。
        lpNumberOfBytesTransferred     一个指针,指向 DWORD,用以表示真正被传输的字节个数。
        bWait                 一个布尔值,用以表示是否要等待操作完成。TRUE 表示要等待。
        
        返回值
            如果 overlapped 操作成功,此函数传回 TRUE。失败则传回 FALSE。GetLastError() 可获得更详细的失败信息。如果 bWait 为 FALSE 而overlapped 还是没有完成,GetLastError() 会传回ERROR_IO_INCOMPLETE。
        
            列表6-1 所显示的程序代码从文件 C:WINDOWSWINFILE.EXE 的第1500 位置处读入 300 个字节。这段代码放在书附盘片的 IOBYFILE 程序中。
                列表6-1 引用自 IOBYFILE.C—overlapped I/O
                    with a signaled file handle
    #0001 int ReadSomething()
    #0002 {
    #0003         BOOL rc;
    #0004         HANDLE hFile;
    #0005         DWORD numread;
    #0006         OVERLAPPED overlap;
    #0007         char buf[512];
    #0008
    #0009         // open the file for overlapped reads
    #0010         hFile = CreateFile( "C:\WINDOWS\WINFILE.EXE",
    #0011                 GENERIC_READ,
    #0012                 FILE_SHARE_READ|FILE_SHARE_WRITE,
    #0013                 NULL,
    #0014                 OPEN_EXISTING,
    #0015                 FILE_FLAG_OVERLAPPED,
    #0016                 NULL
    #0017             );
    #0018         if (hFile == INVALID_HANDLE_VALUE)
    #0019         return -1;

    #0020
    #0021         // Initialize the OVERLAPPED structure
    #0022         memset(&overlap, 0, sizeof(overlap));
    #0023         overlap.Offset = 1500;
    #0024
    #0025         // Request the data
    #0026         rc = ReadFile(
    #0027                 hFile,
    #0028                 buf,
    #0029                 300,
    #0030                 &numread,
    #0031                 &overlap
    #0032             );
    #0033
    #0034         if (rc)
    #0035         {
    #0036             // The data was read successfully
    #0037         }
    #0038         else
    #0039         {
    #0040             // Was the operation queued ?
    #0041             if (GetLastError() == ERROR_IO_PENDING)
    #0042             {
    #0043                 // We could do something else for awhile here...
    #0044
    #0045                 WaitForSingleObject(hFile, INFINITE);
    #0046                 rc = GetOverlappedResult(
    #0047                             hFile,
    #0048                             &overlap,
    #0049                             &numread,
    #0050                             FALSE
    #0051                     );
    #0052             }
    #0053             else
    #0054             {
    #0055                 // Something went wrong
    #0056             }
    #0057         }
    #0058
    #0059         CloseHandle(hFile);
    #0060

    #0061         return TRUE;
    #0062         }

        在这段程序代码中我们得特别注意几点。第一,虽然你要求一个overlapped 操作,但它并不一定就是 overlapped!如果数据已经被放进 cache中,或如果操作系统认为它可以很快速地取得那份数据,那么文件操作就会在ReadFile() 返回之前完成,而 ReadFile() 将传回 TRUE。这种情况下,文件handle 处于激发状态,而对文件的操作可被视为就像 overlapped 一样。
        
        下一个需要注意的是,如果你要求一个文件操作为 overlapped,而操作系统把这个“操作请求”放到队列中等待执行,那么 ReadFile() 和 WriteFile()都会传回 FALSE 以示失败。这个行为并不是很直观, 你必须调用GetLastError() 并确定它传回 ERROR_IO_PENDING,那意味着“overlappedI/O 请求”被放进队列之中等待执行。GetLastError() 也可能传回其他的值,例如 ERROR_HANDLE_EOF,那就真正代表一个错误了。

        请注意 overlapped I/O 如何解决“没有文件指针”这个问题。事实上OVERLAPPED 结构本身就包含了“这个操作应该从哪里开始”的信息。那当然是值得注意的东西,但是在列表6-1 中未显示出来。OVERLAPPED 结构有能力处理 64 位的偏移值,因此即使面对非常巨大的文件也不怕。
        
        为了等待文件操作完成, 我把文件的 handle 交给WaitForSingleObject()。一旦 overlapped 操作完成,该文件 handle 就会成为激发状态。我所举的这个例子过于简单,真实世界里,可能会在程序的某个集中处,等待许多个 handles。

        列表6-1 调用 WaitForSingleObject() 其实是多余的, 因为GetOverlappedResult() 就可以用来等待 overlapped 操作的完成。不过由于实际上你常常会以一个 Wait...() 函数去等待 overlapped 操作完成,所以我才做这样的示范。

  • 相关阅读:
    vue 中input的输入限制
    PC端百度地理围栏、绘制工具以及判断当前坐标是否再围栏中
    js判断鼠标点击的是哪个键
    vue过滤器的使用
    3.Mybatis的配置解析
    2.MyBatis的CRUD操作
    4.JVM类加载器深入解析及重要特性剖析
    3.JVM的接口初始化规则与类加载器准备阶段和初始化阶段的重要意义分析
    2.JVM的类加载器
    1.JVM如何学习
  • 原文地址:https://www.cnblogs.com/azbane/p/7606473.html
Copyright © 2011-2022 走看看