Windows 完成端口编程

article/2025/9/26 18:38:51

Windows 完成端口编程

本文为转载, 原文地址:  http://xingzhesun.blogbus.com/logs/3925649.html

Table of Contents

  • 1 基本概念
  • 2 OVERLAPPED数据结构
  • 3 完成端口的内部机制
    • 3.1 创建完成端口
    • 3.2 完成端口线程的工作原理
    • 3.3 线程间数据传递
    • 3.4 线程的安全退出

1   基本概念

设备—windows操作系统上允许通信的任何东西,比如文件、目录、串行口、并行口、邮件槽、命名管道、无名管道、套接字、控制台、逻辑磁盘、物理磁盘等。绝大多数与设备打交道的函数都是CreateFile/ReadFile/WriteFile等。所以我们不能看到**File函数就只想到文件设备。

与设备通信有两种方式,同步方式和异步方式。同步方式下,当调用ReadFile函数时,函数会等待系统执行完所要求的工作,然后才返回;异步方式下,ReadFile这类函数会直接返回,系统自己去完成对设备的操作,然后以某种方式通知完成操作。

重叠I/O—顾名思义,当你调用了某个函数(比如ReadFile)就立刻返回做自己的其他动作的时候,同时系统也在对I/0设备进行你要求的操作,在这段时间内你的程序和系统的内部动作是重叠的,因此有更好的性能。所以,重叠I/O是用于异步方式下使用I/O设备的。

重叠I/O需要使用的一个非常重要的数据结构  OVERLAPPED  

完成端口—是一种WINDOWS内核对象。完成端口用于异步方式的重叠I/0情况下,当然重叠I/O不一定非使用完成端口不可,还有设备内核对象、事件对象、告警I/0等。但是完成端口内部提供了线程池的管理,可以避免反复创建线程的开销,同时可以根据CPU的个数灵活的决定线程个数,而且可以让减少线程调度的次数从而提高性能。

2   OVERLAPPED数据结构

下面是异步方式使用ReadFile的一个例子

这样就完成了异步方式读文件的操作,然后ReadFile函数返回,由操作系统做自己的事情吧

下面介绍几个与  OVERLAPPED   结构相关的函数 等待重叠I/0操作完成的函数

  HasOverlappedIoCompleted   可以帮助我们测试重叠I/0操作是否完成,该宏对  OVERLAPPED 结构的 Internal 成员进行了测试,查看是否等于  STATUS_PENDING   值。

3   完成端口的内部机制

3.1   创建完成端口

完成端口是一个内核对象,使用时他总是要和至少一个有效的设备句柄进行关联,完成端口是一个复杂的内核对象,创建它的函数是:

通常创建工作分两步:

第一步,创建一个新的完成端口内核对象,可以使用下面的函数:

第二步,将刚创建的完成端口和一个有效的设备句柄关联起来,可以使用下面的函数:

说明


CreateIoCompletionPort
函数也可以一次性的既创建完成端口对象,又关联到一个有效的设备句柄
CompletionKey
是一个可以自己定义的参数,我们可以把一个结构的地址赋给它,然后在合适的时候取出来使用,最好要保证结构里面的内存不是分配在栈上,除非你有十分的把握内存会保留到你要使用的那一刻。
NumberOfConcurrentThreads
通常用来指定要允许同时运行的的线程的最大个数。通常我们指定为0,这样系统会根据CPU的个数来自动确定。

创建和关联的动作完成后,系统会将完成端口关联的设备句柄、完成键作为一条纪录加入到这个完成端口的设备列表中。如果你有多个完成端口,就会有多个对应的设备列表。如果设备句柄被关闭,则表中自动删除该纪录。

3.2   完成端口线程的工作原理

完成端口可以帮助我们管理线程池,但是线程池中的线程需要我们使用beginthreadex来创建,凭什么通知完成端口管理我们的新线程呢?答案在函数   GetQueuedCompletionStatus   。 该函数原型:

这个函数试图从指定的完成端口的I/0完成队列中抽取纪录。只有当重叠I/O动作完成的时候,完成队列中才有纪录。凡是调用这个函数的线程将被放入到完成端口的等待线程队列中,因此完成端口就可以在自己的线程池中帮助我们维护这个线程。

完成端口的I/0完成队列中存放了当重叠I/0完成的结果— 一条纪录,该纪录拥有四个字段,前三项就对应  GetQueuedCompletionStatus   函数的2、3、4参数,最后一个字段是错误信息  dwError   。我们也可以通过调用  PostQueudCompletionStatus   模拟完成了一个重叠I/0操作。

当I/0完成队列中出现了纪录,完成端口将会检查等待线程队列,该队列中的线程都是通过调用GetQueuedCompletionStatus   函数使自己加入队列的。等待线程队列很简单,只是保存了这些线程的ID。完成端口会按照后进先出的原则将一个线程队列的ID放入到释放线程列表中,同时该线程将从等待  GetQueuedCompletionStatus   函数返回的睡眠状态中变为可调度状态等待CPU的调度。

基本上情况就是如此,所以我们的线程要想成为完成端口管理的线程,就必须要调用GetQueuedCompletionStatus   函数。出于性能的优化,实际上完成端口还维护了一个暂停线程列表,具体细节可以参考《Windows高级编程指南》,我们现在知道的知识,已经足够了。

3.3   线程间数据传递

线程间传递数据最常用的办法是在  _beginthreadex   函数中将参数传递给线程函数,或者使用全局变量。但是完成端口还有自己的传递数据的方法,答案就在于  CompletionKey    OVERLAPPED 参数。

CompletionKey   被保存在完成端口的设备表中,是和设备句柄一一对应的,我们可以将与设备句柄相关的数据保存到  CompletionKey   中,或者将  CompletionKey   表示为结构指针,这样就可以传递更加丰富的内容。这些内容只能在一开始关联完成端口和设备句柄的时候做,因此不能在以后动态改变。

OVERLAPPED   参数是在每次调用  ReadFile   这样的支持重叠I/0的函数时传递给完成端口的。我们可以看到,如果我们不是对文件设备做操作,该结构的成员变量就对我们几乎毫无作用。我们需要附加信息,可以创建自己的结构,然后将  OVERLAPPED   结构变量作为我们结构变量的第一个成员,然后传递第一个成员变量的地址给  ReadFile   函数。因为类型匹配,当然可以通过编译。当GetQueuedCompletionStatus   函数返回时,我们可以获取到第一个成员变量的地址,然后一个简单的强制转换,我们就可以把它当作完整的自定义结构的指针使用,这样就可以传递很多附加的数据了。太好了!只有一点要注意,如果跨线程传递,请注意将数据分配到堆上,并且接收端应该将数据用完后释放。我们通常需要将ReadFile这样的异步函数的所需要的缓冲区放到我们自定义的结构中,这样当*GetQueuedCompletionStatus* 被返回时,我们的自定义结构的缓冲区变量中就存放了I/0操作的数据。

CompletionKey    OVERLAPPED   参数,都可以通过  GetQueuedCompletionStatus   函数获得。

3.4   线程的安全退出

很多线程为了不止一次的执行异步数据处理,需要使用如下语句

那么如何退出呢,答案就在于上面曾提到的  PostQueudCompletionStatus   函数,我们可以用它发送一个自定义的包含了  OVERLAPPED   成员变量的结构地址,里面包含一个状态变量,当状态变量为退出标志时,线程就执行清除动作然后退出。


Author: guolihui  <guolihui112@gmail.com>

Date: 2009-12-31 11:19:24

HTML generated by org-mode 6.30c in emacs 23


http://chatgpt.dhexx.cn/article/VCbQjoF9.shtml

相关文章

完成端口IOCP详解

本系列里完成端口的代码在两年前就已经写好了&#xff0c;但是由于许久没有写东西了&#xff0c;不知该如何提笔&#xff0c;所以这篇文档总是在酝酿之中……酝酿了两年之后&#xff0c;终于决定开始动笔了&#xff0c;但愿还不算晚….. 这篇文档我非常详细并且图文并茂的介绍了…

Win socket编程--IOCP完成端口模型

引言 要想编写一个高性能的服务器应用程序&#xff0c;必须实现一个高效的线程模型。让太少或者太多的服务器线程来处理客户的请求&#xff0c;都可能导致性能问题。例如&#xff0c;如果一个服务器创建单个线程来处理所有的请求&#xff0c;那么客户端可能长期等待而得不到响…

深度探索I/O完成端口

引言 要想编写一个高性能的服务器应用程序&#xff0c;必须实现一个高效的线程模型。让太少或者太多的服务器线程来处理客户的请求&#xff0c;都可能导致性能问题。例如&#xff0c;如果一个服务器创建单个线程来处理所有的请求&#xff0c;那么客户端可能长期等待而得不到响…

Windows中I/O完成端口机制详解

Windows中I/O完成端口机制详解 引言 要想编写一个高性能的服务器应用程序&#xff0c;必须实现一个高效的线程模型。让太少或者太多的服务器线程来处理客户的请求&#xff0c;都可能导致性能问题。例如&#xff0c;如果一个服务器创建单个线程来处理所有的请求&#xff0c;那么…

c++使用完成端口实现服务器的高性能并发

如何使用c,借助完成端口完成大并发服务器的搭建,是今天要讨论的问题&#xff0c;套路如下&#xff1a; 套路总结一下&#xff1a; 创建完成端口 依据CPU核数创建一定数量的线程 线程中不断调用GetQueuedCompletionStatus检查完成端口状态&#xff0c;分别给予处理 创建一个…

C#高性能大容量SOCKET并发完成端口例子(有C#客户端)完整实例源码

遥望星空 好好干&#xff0c;有前途&#xff01; 博客园首页新随笔联系管理订阅 随笔- 1082 文章- 0 评论- 151 C#高性能大容量SOCKET并发(转) C#高性能大容量SOCKET并发&#xff08;零&#xff09;&#xff1a;代码结构说明 C#高性能大容量SOCKET并发&#xff08;一…

完成端口学习笔记(一):完成端口+控制台 实现文件拷贝

最近在整理手里一个项目的后台服务端归档程序&#xff0c;重新梳理了一下有关“完成端口”的知识&#xff0c;发现还是有很多模棱两可的地方&#xff0c;下面记录一下再次学习的点滴&#xff0c;该篇博文还会有后续的补充章节&#xff0c;不知道什么时间会再补充^_^。 IO概念 还…

Socket编程模型之完成端口模型

转载请注明来源&#xff1a;http://blog.csdn.net/caoshiying?viewmodecontents 一、回顾重叠IO模型 用完成例程来实现重叠I/O比用事件通知简单得多。在这个模型中&#xff0c;主线程只用不停的接受连接即可&#xff1b;辅助线程判断有没有新的客户端连接被建立&#xff0c;如…

完成端口(IOCP)详解[2/2](转载)

版权声明&#xff1a;本文为CSDN博主「PiggyXP」的原创文章&#xff0c;遵循CC 4.0 BY-SA版权协议&#xff0c;转载请附上原文出处链接及本声明。 原文链接&#xff1a;https://blog.csdn.net/piggyxp/article/details/6922277 五 使用完成端口的基本流程 说了这么多的废话&a…

Windows io完成端口

Windows 提供一种称为I/O完成端口(I/O Completion Port)机制&#xff0c;能够让I/O的完成处理交由一个专门的线程池来完成&#xff0c;而线程池的线程数量是一个可配置的参数。这种做法将I/O请求的发起动作与完成处理分离到了不同的线程中。 I/O完成端口是内核对象。个人的感觉…

完成端口(Completion Port)详解

http://blog.csdn.net/piggyxp/article/details/6922277 手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解 ----- By PiggyXP(小猪) 前 言 本系列里完成端口的代码在两年前就已经写好了&#xff0c;但是由于许久没有写东西了&#xff0c;不知该如何提笔&#xf…

完成端口(CompletionPort)详解 - 手把手教你玩转网络编程系列之三

手把手叫你玩转网络编程系列之三 完成端口(Completion Port)详解 ----- By PiggyXP(小猪) 前 言 本系列里完成端口的代码在两年前就已经写好了&#xff0c;但是由于许久没有写东西了&#xff0c;不知该如何提笔&#xff0c;所以这篇文档总是在酝酿之中……酝酿了两年之后&…

树同构-树哈希

树同构-树哈希 题目描述 题解 对于无根树&#xff0c;由于数据范围较小&#xff0c;可以直接以每个点为根dfs一次&#xff0c;维护其树哈希的值&#xff0c;然后用并查集维护 &#xff08;若数据范围大一些&#xff0c;可以以树的重心跑dfs&#xff09; 代码实现 #include&…

2.3 树的同构(树,c)

树的同构 树的同构输入格式:输出格式:输入样例1&#xff08;对应图1&#xff09;&#xff1a;输出样例1:输入样例2&#xff08;对应图2&#xff09;&#xff1a;输出样例2: 题意理解输入两棵二叉树的信息&#xff0c;判断是否同构&#xff08;对应图1&#xff09; 求解思路二叉…

03-树1 树的同构

题目 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2&#xff0c;则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的&#xff0c;因为我们把其中一棵树的结点A、B、G的左右孩子互换后&#xff0c;就得到另外一棵树。而图2就不是同构的。 图1 图2 现给…

『树同构的判定(树Hash)』CF718D:Andrew and Chemistry

题目描述 题解 这道题目的难点在于如何判断树的同构&#xff0c;这就是所谓的树的哈希。 我们假设需要求解以x为根的子树的hash值&#xff0c;我们可以将子树的hash值存储到vector内&#xff0c;排序以后用map来判断重复。这个写法十分简单。具体如下&#xff1a; int dfs(i…

数据结构之树的同构

目录 前言 题意理解 求解思路 二叉树表示 程序框架搭建 读数据建二叉树 二叉树同构判别 前言 本篇主要讲有关二叉树的同构判断。 题意理解 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2&#xff0c;则称这两棵树是“同构”的。 例如&#xff1a; 左图…

2020牛客多校10:Identical Trees(树hash + 树同构 + 费用流模板)

题意&#xff1a;给出两棵同构的有根树&#xff0c;同构修改点的标号使得两棵树完全一样&#xff0c;至少需要修改多少次。 分析&#xff1a;肯定是将子树和另外一棵的某个子树对应&#xff0c;而两棵子树的问题是一个子问题&#xff0c;显然只有同构的子树才可以对应&#xf…

哈希算法在判定树同构方面的应用(下)

哈希算法在判定树同构方面的应用 在上一篇文章中我们介绍了 枚举根节点哈希 和 求重心哈希 两种方法来判断两棵无根树是否同构。 但是如果有些题目中我必须要计算出每个根节点的 f f f 值&#xff0c;且 n ≤ 1 e 5 n\le 1e5 n≤1e5&#xff0c;我们要怎么办呢&#xff1f;…

树的同构判断

使用递归的思路解决树的同构的判断 给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2&#xff0c;则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的&#xff0c;因为我们把其中一棵树的结点A、B、G的左右孩子互换后&#xff0c;就得到另外一棵树。而图2…