IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> [笔记]Windows核心编程《九》同步设备I/O和异步设备I/O -> 正文阅读

[系统运维][笔记]Windows核心编程《九》同步设备I/O和异步设备I/O

参考1
参考2
参考3
参考4
Windows核心编程-CreateFile详解
基于visual c++之windows核心编程代码分析(6)分配和释放可读可写的虚拟内存页面
基于visual c++之windows核心编程代码分析(24)IO控制、内核通信
基于visual c++之windows核心编程代码分析(25)检测U盘控制开关机
【CreateFileA】创建或打开文件或I / O设备
微软 调用 DeviceIoControl Demo
DeviceIoControl 函数详细解析

打开和关闭设备

设备:定义为能与之通信的任何东西。

表1:各种设备及其常见用途

设备常见用途
文件永久存储任何数据
目录属性和文件压缩的设置
逻辑磁盘驱动器格式化驱动器
物理磁盘驱动器访问分区表
串口通过电话线传输数据
并口将数据传输至打印机
邮件槽一对多数据传输,通常是通过网络传到另一台运行Windows的机器上
命名管道一对一数据传输,通常是通过网络传到另一台运行Windows的机器上
匿名管道单机上的一对一数据传输(绝对不会跨网络)
套接字报文或数据流的传输,通常是通过网络传到任何支持套接字的机器上(机器不一定要运行Windows操作系统)
控制台文本窗口的屏幕缓存

Windows允许我们以相同的方式来从设备读取数据和向设备写入数据,而不必关心他是何种类型的设备。
当然各种设备之间还是存在差异。
例如对于串口来说,设置波特率是合理的,但在使用命名管道来进行跨网络传输,波特率就没有意义。
文件是最常用的设备之一。

表2:用来打开各种设备的函数

设备用来打开设备的函数
文件CreateFile (pszName 为路径或UNC路径名)
目录CreateFile (pszName 为路径或UNC路径名). 如果在调用CreateFile的时候指定 FILE_ FLAG_BACKUP_SEMANTICS 标志,那么Windows允许我们打开一个目录。打开目录使我们能够改变目录的属性和它的时间戳。
逻辑磁盘驱动器CreateFile (pszName is “//./x :”). 如果指定的字符串是 "//./x :"的形式,那么Windows允许我们打开一个逻辑磁盘驱动器,其中的x是驱动器的盘符。打开驱动器使我们能够格式化驱动器或检测驱动器媒介的大小。
无力磁盘驱动器CreateFile (pszName 为 “//./PHYSICALDRIVEx “). 如果指定的字符串是”//./PHYSICALDRIVEx " 的形式,那么Windows允许我们打开一个屋里磁盘驱动器,其中的x是物理驱动器号。例如,为了读写用户的第一个物理驱动器的扇区,我们应该制定”//./PHYSICALDRIVE0".打开物理驱动器使我们能够直接访问硬盘的分区表。打开物理驱动器有潜在的危险,错误地写入设备可能会导致操作系统的文件系统无法访问磁盘的内容
串口CreateFile (pszName 为 "COMx ").
并口CreateFile (pszName 为 "LPTx ").
邮件槽服务器CreateMailslot (pszName 为 "//./mailslot/mailslotname ").
命名管道服务器CreateNamedPipe (pszName 为 "//./pipe/pipename ").
命名管道客户端CreateFile (pszName 为 "//servername /pipe/pipename ").
匿名管道CreatePipe 用来打开服务器和客户端
套接字socket , accept , 或AcceptEx .
控制台CreateConsoleScreenBuffer 或 GetStdHandle

细看CreateFile函数

HANDLE CreateFileW(
  LPCWSTR               lpFileName,
  DWORD                 dwDesiredAccess,
  DWORD                 dwShareMode,
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  DWORD                 dwCreationDisposition,
  DWORD                 dwFlagsAndAttributes,
  HANDLE                hTemplateFile
);

大多数以句柄为返回值的Windows函数在失败的时候会返回NULL。但是,CreateFile返回INVALID_HANDLE_VALUE

使用文件设备

取得文件的大小

WINBASEAPI
BOOL
WINAPI
GetFileSizeEx(
    _In_ HANDLE hFile,
    _Out_ PLARGE_INTEGER lpFileSize
    );

hFile 一个已经打开的文件句柄;
lpFileSize是一个LARGE_INTEGER联合类型的地址。

设置文件指针的位置

文件内核对象有一个文件指针64位偏移量,表明应该在哪里执行下一次同步读取或写入操作。初始值为0
例如一下代码先读取前10个字节到缓存,然后再把后10个字节读取到缓存中。

执行同步设备I/O

同步设备IO, 可以是文件,邮件槽,管道,套接字等。
最常见的操作就是读写数据。

WINBASEAPI
_Must_inspect_result_
BOOL
WINAPI
ReadFile(
    _In_ HANDLE hFile,
    _Out_writes_bytes_to_opt_(nNumberOfBytesToRead, *lpNumberOfBytesRead) __out_data_source(FILE) LPVOID lpBuffer,
    _In_ DWORD nNumberOfBytesToRead,
    _Out_opt_ LPDWORD lpNumberOfBytesRead,
    _Inout_opt_ LPOVERLAPPED lpOverlapped
    );
WINBASEAPI
BOOL
WINAPI
WriteFile(
    _In_ HANDLE hFile,
    _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer,
    _In_ DWORD nNumberOfBytesToWrite,
    _Out_opt_ LPDWORD lpNumberOfBytesWritten,
    _Inout_opt_ LPOVERLAPPED lpOverlapped
    );

hFile:表示要访问的设备句柄。 (打开设备时不要执行FILE_FLAG_OVERLAPPED标志,否则系统会认为我们想要与设备执行异步IO)
lpBuffer:执行一个缓存,函数会把数据读取到该缓存中,或者把缓存中的数据写入设备。
nNumberOfBytesToRead:(要读取的字节)
nNumberOfBytesToWrite :(要写入多少字节)
lpNumberOfBytesRead:(返回实际读取的字节)
lpNumberOfBytesWritten:(返回实际写入的字节)
lpOverlapped:(设置为NULL 表示执行同步读写)
ReadFile:(用于使用GENERIC_READ打开的设备)
WriteFile:(用于使用GENERIC_WRITE打开的设备)

异步设备I/O基础

和计算机执行的其他操作相比,设备IO是其中最慢,最不可预测的操作之一。
异步IO就是,将IO请求加入请求队列,由设备的驱动程序来执行IO,应用程序当前的线程不会被挂起。
CreateFile dwFlagsAndAttributes参数中指定FILE_FLAG_OVERLAPPED标志来打开设备。

接受I/O请求完成通知

windows提供了4种不同方法来接收IO请求已经完成的通知。

技术摘要
触发设备内核对象当向一个设备同时发出多个I/O请求的时候,这种方法没什么用。它允许一个线程发出I/O请求,另一个线程对结果进行处理。
触发事件内核对象这种方法允许我们向一个设备同时发出多个I/O请求。它允许一个线程发出I/O请求,另一个线程对结果进行处理。
使用可提醒I/O这种方法允许我们向一个设备同时发出多个I/O请求。发出I/O请求的线程必须对结果进行处理。
使用I/O 完成端口这种方法允许我们向一个设备同时发出多个I/O请求。它允许一个线程发出I/O请求,另一个线程对结果进行处理。这项技术具有高度的伸缩性和最佳的灵活性。

触发设备内核对象

ReadFile和WriteFile函数将IO请求添加到队列之前,会先将设备内核对象设置为未触发状态。当设备驱动完成了请求以后,驱动程序会将设备内核对象设置为非触发状态。

一旦一个线程触发了一个异步I/O请求,该线程将会继续运行,以执行其它有用的任务。但即便如此,线程最终海华丝需要与I/O操作的完成状态进行同步。我 们会继续运行到线程代码中的一个点,在这个点上,除非设备数据已经被载入到缓存中,否则线程将无法执行后继操作。在Windows中设备内核对象可以用来 进行线程同步,因此对象既可能处于触发状态,也可能处于未触发状态。ReadFile和WriteFile函数在将I/O请求添加到队列之前,会先将设备 内核对象设为未触发状态,当设备驱动程序完成了请求之后,驱动程序会将设备内核对象设为触发状态。

可提醒I/O

当系统创建一个线程的时候,会同时创建一个与线程相关联的队列。这个队列被称为异步过程调用(asynchronous procedure call,APC)队列。当发出一个I/O请求的时候,我们可以告诉设备驱动程序在调用线程的APC队列中添加一项。

I/O完成端口

I/O 完成端口背后的理论是并发运行的线程的数量必须有一个上限——也就是说,同时发出的500个客户请求不应该允许出现500个可运行的线程。如果能在应用程 序初始化的时候创建一个线程池,并让线程池中的线程在应用程序运行期间一直保持可用状态,那么服务应用程序的性能就能得到提高。I/O完成端口的设计初衷 就是与线程池配合使用。

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-09-26 10:36:28  更:2021-09-26 10:38:50 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 16:56:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码