异步I/O之文件

Posted _xiaohaige

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步I/O之文件相关的知识,希望对你有一定的参考价值。

一、概念:

  1.1、打开设备的操作会向操作系统发送请求,CreateFile函数会直接返回,而不会去等待操作完成。

  1.2、此时操作系统会发现这个请求,然后操作系统会来进行实际的操作,当操作完成之后,

  1.3、会设置一些标志,也就是通知。

  1.4、在操作系统进行实际操作的时候,我可以来做一些想要做的操作,当通知来了的时候,I/O完成。

  1.5、这使得我们无须等待CreateFile操作的完成,就能进行其他的操作。

  1.6、为什么会产生阻塞?

    1.6.1、进程:程序运行的一块空间,存储(一个)。

    1.6.2、线程:程序实际运行的单位,工作,和 CPU 打交道的是线程(多个)。

    1.6.3、WaitForSingleObject(hFile, INFINITE) //阻塞,等待操作完成。

1.7、OVERLAPPED结构体:

1.7.1、
typedef struct _OVERLAPPED {
    ULONG_PTR Internal;
    ULONG_PTR InternalHigh;
    union {
        struct {
            DWORD Offset;    //64位的偏移量,低位。表示从哪里开始。
            DWORD OffsetHigh;    //高位。表示结束的位置。
        };
    PVOID Pointer;
    };
    HANDLE hEvent;
} OVERLAPPED, *LPOVERLAPPED;                        

 

1.8、在进行一步I/O操作的时候有四种可用的提醒操作完成的方式:

  1.8.1、使用设备内核对象。

if (!bRet && GetLastError() == ERROR_IO_PENDING)
{
  std::cout << "正在等待IO完成。。。。。" << std::endl;
  WaitForSingleObject(hFile, INFINITE); //使用这个函数进行阻塞,等待I/O完成。
}

  1.8.2、使用事件内核对象。

    1.8.2.1、唯一的只有一个。

    1.8.2.2、所谓的内核对象都是独立于我们的程序的,它们是属于操作系统的。

char readBuffer[MAXBYTE] = { 0 };
OVERLAPPED readOV = { 0 };
readOV.Offset = 0;
readOV.hEvent = CreateEvent(nullptr, true, false, _T("readEvent")); //创建了一个事件内核对象。
ReadFile(hFile, readBuffer, MAXBYTE, nullptr, &readOV); //会直接发送一个请求,然后继续往下执行。

char writeBuffer[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
OVERLAPPED writeOV = { 0 };
writeOV.Offset = 0;
writeOV.hEvent = CreateEvent(nullptr, true, false, _T("writeEvent")); //创建了一个事件内核对象。
WriteFile(hFile, writeBuffer, strlen(writeBuffer), nullptr, &writeOV); //会直接发送一个请求,然后继续往下执行。

//其他线程:

HANDLE hOverLapped[2] = { 0 };
hOverLapped[0] = readOV.hEvent;
hOverLapped[1] = writeOV.hEvent;

while (true)
{
  DWORD dwCase = WaitForMultipleObjects(2, hOverLapped, FALSE, INFINITE);//还是需要这个函数进行等待。
  switch(dwCase - WAIT_OBJECT_0)
  {
  case 0:
    //读完成
    std::cout << "read is access" << std::endl;
    break;
  case 1:
   //写完成
    std::cout << "write is access" << std::endl;
    break;
  }
}

  1.8.3、可提醒I/O。

    1.8.3.1、发送请求 -> 做自己的事情 -> 判断请求是否完成。 异步I/O

    1.8.3.2、发送请求 -> 完成后,操作系统提醒我。这种方式明显的比上面的方式要好。当然这样能不能做到呢?

    1.8.3.3、可提醒I/O操作可以完成:

      APC机制:工厂(进程) -> 工人(线程):当线程闲的时候(前提) ->APC列表中的事情(自动的执行)(线程为可提醒状态下)

    1.8.3.4、可提醒I/O就是基于APC机制来做的异步I/O操作。但并不是太好用。

    1.8.3.5、虽然说可提醒I/O并不好用,但是APC机制还是很好用的。

    1.8.3.6、当我们的线程处在可提醒状态的话呢,线程就会去执行APC的回调函数。

  1.8.4、I/O完成端口。

    1.8.4.1、概述:最为方便,也是最为科学的一种方式。

以上是关于异步I/O之文件的主要内容,如果未能解决你的问题,请参考以下文章

asyncio 是不是支持文件操作的异步 I/O?

网络I/O模型---同步异步阻塞非阻塞之惑

为啥说nodejs是异步非阻塞

监控文件描述符的六种方式(进程监控selectpoll非阻塞轮询I/O异步I/O线程监控)

网络编程之五种I/O模型

简明网络I/O模型---同步异步阻塞非阻塞之惑