I/O completion port 运作过程中令人迷惑的部分就是,当一个线程被阻塞
住时,它将发出通告,并提交另一个线程。假设在单一 CPU 的系统中,有两
个线程都正在一个 I/O completion port 上等待,线程1被唤醒,并且从网络上
获得一包数据。为了服务这个数据包,线程1必须从磁盘中读一个文件,所以
它调用 CreateFile() 和 ReadFile(),但不在 overlapped 模式中。
Completion port 于是通告说线程1被磁盘 I/O 滞留了,并且提交线程2
以使“目前作用中的线程个数”到达需求数量。
当线程1从磁盘操作中返回时,或许现在有两个线程同时在执行——甚至
即使“作用中的线程个数”应该只是 1(因为 CPU 个数只是 1)。这一行为
令人惊讶,但却是正确的。Completion port 不会再提交另一个线程,除非“作
用中的线程个数”再次降到 1 以下。
操作

当线程1从磁盘操作中返回时,或许现在有两个线程同时在执行——甚至
即使“作用中的线程个数”应该只是 1(因为 CPU 个数只是 1)。这一行为
令人惊讶,但却是正确的
为什么有2个同时执行?
当你一产生这些线程时,它们都应该在 completion port 上等待。当线程
开始为各个“请求”服务时,池子里的线程的组织如下:
目前正在执行的线程
+ 被阻塞的线程
+ 在 completion port 上等待的线程
--------------------------------------------
= 池子里的所有线程的个数
阻塞和等待有什么区别?

解决方案 »

  1.   

    在这里 等待的意思是线程不可调度, 阻塞的意思是线程可调度没有获得CPU.2个同时执行的意思就是有2个线程在可以调度, 这两个线程就会竞争CPU.
    如果线程1没有被阻塞, 只会有线程1能被调度, 没有竞争线程.
      

  2.   

    假设在单一 CPU 的系统中,有两
    个线程都正在一个 I/O completion port 上等待,线程1被唤醒,并且从网络上
    获得一包数据。为了服务这个数据包,线程1必须从磁盘中读一个文件,所以
    它调用 CreateFile() 和 ReadFile(),但不在 overlapped 模式中。这段话又如何理解?1.  我是这样立即的, win32多线程 这本书 是侯捷翻译的,实话,翻译质量很烂, 而且印刷有不少错误,原作者在讲解  iocp的时候,也是引入了关于网络方面的例子,但是 作者没有用WSARecv之类的函数去接受,发送数据,而是采用 ReadFile, WriteFile.也是在这本书中,我才明白,原来,ReadFile可以接受网络的数据。2.  或许作用没有使用WSARecv,而是采用Readfile, 这个函数貌似有些特殊性, 需要从磁盘读取一些东西,然后再从网络读取数据,    在磁盘读取的时候,  好像和重叠io结构体没有关系了,只有从网络读取的时候才有关系。不知道阁下  对我提的2点,有什么看法,请指出,谢谢
      

  3.   

    这里作者想要说明白的是IOCP特别的线程调度方式.
    IOCP的线程的调度特性概况来讲,就是,当有数据到来时,如果在IOCP上面有线程可以调度来处理数据,
    而又没有超过调度上限, IOCP可以保证会有线程被立即调度来处理数据.这个特性也就是IOCP高效的官方保证, IOCP所有的设计和原理说明
    都是围绕着这个特性来的.线程1被唤醒,并且从网络上获得一包数据。这么说严格来说其实时序上是错的.
    是先从网络上获得一包数据, 然后线程1被唤醒.
    线程1被唤醒的时候, 数据已经在线程1手中(已经在ring3提供的缓冲区中).
    这是IOCP的特性的第一个方面的解释.
    作者为了强调这个特性, 又举了你说的这个例子.
    当线程1被调度然后阻塞的时候, IOCP依然会满足上面的特性,
    会调度线程2来处理数据(即保证有线程会被立即调度来处理数据).作者用以阻塞线程1的方式以同步的方式读写文件,
    因为这种方式大家都能接受而不需要做过多解释.CreateFile/ReadFile/WriteFile可以创建(打开)和读写Windows上的几乎所有资源,
    我觉得这个设计是受Unix上面所有设备都是文件的影响.
    我个人不觉得这几个函数有什么特殊性.作者特别强调没有重叠IO是因为 IOCP不只是能用于网络,
    大多数Windows的异步操作都有对IOCP的支撑.如果线程1对文件的操作有重叠IO,线程1就能顺利完成任务,回到IOCP中.
    因为线程切换是非常耗费资源的事,所以当线程1回到IOCP时,
    如果此时有数据, 数据肯定归线程1处理, 这样就没线程2什么事了.这样的场景体现不出IOCP跟普通异步模式的优势.
    总之IOCP是很麻烦的事, 自己多写点错误的代码来了解IOCP的特性.我原先栽在IOCP上面的事获取能帮你理解这个特性.
    WSASend(buf)
    need_free_buf = buf;void OnSend()
    {
    FreeBuffer(need_free_buf);
    }
    这段代码看起来应该没什么问题,
    但是在多核CPU中,
    在异步WSASend尚未返回的时候, Send事件已经完成.
    IOCP的特性就会超长发挥, IOCP会立即调度线程2来执行OnSend函数.
    后果自然而知.