重叠_重叠保留法 - CSDN
精华内容
参与话题
  • 判断两个矩形是否重叠

    万次阅读 多人点赞 2017-11-27 00:20:47
    判断两个矩形是否重叠关于如何判断两个矩形重叠,这是我在实际项目开发当中曾经遇到过的问题:“判断图像中检测到的两个人脸框矩形是否有重叠部分,并计算重叠大小,从而确认是否为同一个人脸”。后来,在浏览博客时...

    判断两个矩形是否重叠

    关于如何判断两个矩形重叠,这是我在实际项目开发当中曾经遇到过的问题:“判断图像中检测到的两个人脸框矩形是否有重叠部分,并计算重叠大小,从而确认是否为同一个人脸”。后来,在浏览博客时,也发现也有人将这个问题当做面试题目,并进行过讨论,但是,列出的代码过于繁杂,不敢恭维。所以,写下这篇博文,并贴出代码,供大家参考。

    前提

    1. 两个矩形的边均与x轴或y轴平行,即轴对齐的矩形
    2. 将第一个矩形记做A,第二个矩形记做B
    3. 判断矩阵A与矩阵B是否重叠(边沿重叠也认为是重叠)

    讨论

    1. 第一种方案,正向思维
      按照一般的思路,先列举出所有的矩形重叠的情况,然后,判断是否是其中一种,如图所示,共有四种重叠情况,我们使用紫色代表矩形A,红色代表矩形B,并分别用p1,p2,p3,p4代表对应的左上角与右下角。如果依次判断,过于复杂,而且容易出错,这里我们不再进行代码实现。
      两矩形的重叠情况
    2. 第二种方案,反向思维
      反向思考,我们不妨先解决出“不重叠”的情况,如图,我们画出了一个并怎么漂亮的图,看起来十分复杂,但是,实际上,相比第一种方案,更易表示。即B矩阵,可能在A的左侧、右侧、上侧、下侧。如果用公式表示,即
      (p2.yp3.y)(p1.yp4.y)(p2.xp3.x)(p1.xp4.x)
      则,两个矩阵重叠时,公式为
      ¬[(p2.yp3.y)(p1.yp4.y)(p2.xp3.x)(p1.xp4.x)]
      根据德·摩根定律可转换为
      (p2.y>p3.y)(p1.y<p4.y)(p2.x>p3.x)(p1.x<p4.x)
      两矩形不重叠情况

    解决方案

    根据上述第二种情况分析,我们可以进行代码的实现,如下

    #include <iostream>
    using namespace std;
    
    //矩阵位置坐标
    typedef struct Rect {
        Rect(int x, int y, int width, int height)
            : x(x), y(y), width(width), height(height)
        {}
        int x;          //矩形左上角x坐标
        int y;          //矩形左上角y坐标
        int width;      //矩形宽度
        int height;     //矩形高度
    } Rect;
    
    
    /**
     * @brief 判断两个轴对齐的矩形是否重叠
     * @param rc1 第一个矩阵的位置
     * @param rc2 第二个矩阵的位置
     * @return 两个矩阵是否重叠(边沿重叠,也认为是重叠)
     */
    bool isOverlap(const Rect &rc1, const Rect &rc2)
    {
        if (rc1.x + rc1.width  > rc2.x &&
            rc2.x + rc2.width  > rc1.x &&
            rc1.y + rc1.height > rc2.y &&
            rc2.y + rc2.height > rc1.y
           )
            return true;
        else
            return false;
    }
    
    
    int main()
    {
        Rect rc1(0,0,10,10), rc2(11,11,2,2);
        if (isOverlap(rc1, rc2))
            cout << "Rectangles Overlap";
        else
            cout << "Rectangles Don't Overlap";
        return 0;
    }

    附录

    此处,本文也提供一个计算该两个矩阵重叠面积比例的函数实现,虽然所用公式看起来不甚相同,但是,可以很容易推出来,实际上是一样的。(注意,此代码中使用了OpenCV内部结构)

    /**
     * @brief 计算两个矩形的相交面积及组合面积,同时计算相交面积占组合面积的比例
     * @param 第一个矩形的位置
     * @param 第二个矩形的位置
     * @param 两个矩阵相交的面积大小
     * @param 两个矩阵组合的面积大小
     * @return 两个矩阵相交面积占组合面积的比例,即重合比例。如果组合面积为0,则返回0
     */
    float computRectJoinUnion(const CvRect &rc1, const CvRect &rc2, float& AJoin, float& AUnion)
    {
        CvPoint p1, p2;                 //p1为相交位置的左上角坐标,p2为相交位置的右下角坐标
        p1.x = std::max(rc1.x, rc2.x);
        p1.y = std::max(rc1.y, rc2.y);
    
        p2.x = std::min(rc1.x +rc1.width, rc2.x +rc2.width);
        p2.y = std::min(rc1.y +rc1.height, rc2.y +rc2.height);
    
        AJoin = 0;
        if( p2.x > p1.x && p2.y > p1.y )            //判断是否相交
        {
            AJoin = (p2.x - p1.x)*(p2.y - p1.y);    //如果先交,求出相交面积
        }
        float A1 = rc1.width * rc1.height;
        float A2 = rc2.width * rc2.height;
        AUnion = (A1 + A2 - AJoin);                 //两者组合的面积
    
        if( AUnion > 0 )
            return (AJoin/AUnion);                  //相交面积与组合面积的比例
        else
            return 0;
    }
    展开全文
  • 这两天做小项目的时候遇见了这个问题,分享给跟我有同样问题的同学 如图所示 头像与对话框需要两个图片叠加才可以解决。 .right-relative{ position:relative; color:#000; width:500px;....right-a{ position:...

    这两天做小项目的时候遇见了这个问题,分享给跟我有同样问题的同学
    如图所示在这里插入图片描述
    头像与对话框需要两个图片叠加才可以解决。

    .right-relative{
        position:relative; 
        color:#000; 
        width:500px; 
        height:400px;
        margin: 0 auto;
    } 
    .right-a{ position:absolute; left:800px; top:30px; width:200px; height:100px}  
    .right-b{ position:absolute; left:899px; top:10px;  width:400px; height:200px} 
    .right_name{
        position: absolute;
        padding: 0px 4px 15px 40px;
        color: blue;
        font-family:verdana;
        font-size: 20px;
    
    }
    .right_to{
        color: #666;
        font-family:verdana;
        position: absolute;
        padding: 2px 10px 2px 9px;
    }
    
     <div class="right_elative">
                <div class="right-a">
                    <img width="150" height="150" src="右.jpg"/>  
                    <br>
                    <span class="right_name">SUE</span>
                    <br>
                    <span class="right_to">local experts</span>
                </div>
                <div class="right-b">
                    <img width="90" height="90" src="聊天信息.png" />
                </div>   
         </div>
    

    代码解释
    使用position实现绝对定位.
    对父级设置position:relative属性,对其子级设置position:absolute加上left或right和top或bottom实现子级在父级内任意定位。
    在原始情况下重叠是按DIV代码本身顺序排列,越后输入的DIV盒子其越靠前(浮在上面)。

    这样处理,两个图像就不会因为浏览器缩放问题而错位啦~

    展开全文
  • 1.背景 假设有两条轨迹,一条是预定轨迹,一条是实际轨迹,分别为L1、L2。L1由点(A1、A2、A3、…、AN)组成,L2由(B1、B2、B3、…、BM)组成。现在给出了一个容差范围,即L2上的点能与L1这条预定路线的垂直容差...

    转载于:http://www.cnblogs.com/naaoveGIS/

    1.背景
    假设有两条轨迹,一条是预定轨迹,一条是实际轨迹,分别为L1、L2。L1由点(A1、A2、A3、…、AN)组成,L2由(B1、B2、B3、…、BM)组成。现在给出了一个容差范围,即L2上的点能与L1这条预定路线的垂直容差范围Range,求L2上满足要求的实际点。

    这个需求我们实际可以分为两种情况来考虑,一种是此需求单纯的仅仅是要求得到与L1能有一定匹配度的点。但是,如果我们深入分析,会发现L1作为一条线,其本身是有方向性的,如果我们还将线的方向性考虑进来,即L2的点不仅要在与L1的Range范围内,还要此时的点的前进趋势与L1是相同的。

    当然,我们通过AGS或者GeoServer之类的NA服务是可以实现最邻路径生成的方法的,这个方法我们留在我的从底层谈WebGIS的设计实现系列中跟大家一起探讨。这里我要跟大家讨论一种效率更高的方法,直接通过数据库的存储过程来实现。

    我在上面提到的两种情况(不考虑方向性和考虑方向性),这两者是层层递进的。我们首先考虑如何通过不考虑方向性来解决。然后再进一步探讨如果有方向性,我们该用什么思路去实现。

    2.不考虑方向性的算法实现
    2.1进一步简化问题
    这里,首先我们将问题进一步简化,即如何判断一个点是否落在两个点组成的线的容差范围内,距离描述为:a点、b点两个计划点,c点为实际点,现在要判断c点是否在a点和b点连接成的直线的容差范围内。

    2.2解决简化问题的思路
    我将解决步骤分为三步。分别为:1.粗略判断;2.判断是否落在线外;3.垂线判断。

    详细过程便是:

    A.粗略判断,c点和a点以及b点的连线是否在容差范围内,即ac或者bc是否在容差范围内。如果是,返回true。否则,进一步判断。

    B.判断c点是否在ab直线的外侧,即c点到ab的垂足在ab的延长线上(如果是这种情况,只给一个容差范围是很难确定是否符合标准的,需要多个与容差有关的参数,比如水平容差和垂直容差等,为了简化,此种情况下,直接返回false)。如果垂足在ab上,则进行下一步。

    C.算出c点到ab的垂线距离d。判断d是否在容差范围内,如果在,返回true;否则,返回false。

    2.3实现判断点是否在线范围内(使用存储过程)
    利用海伦公式求点到线段的距离。

    传递的参数中。x0、y0、x1、y1为预定轨迹的两个坐标(P0,P1),x2、y2为第三个坐标(实际位置S)的坐标, fRange为比对距离,return 0 超出,return 1未超出。

    function getNearestDistance(x0 in number,y0 in number,x1 in number,y1 in number,x2 in number,y2 in number,fRange in number := 1,distance out number) return integer is

    fa number(15,3);
    
    fb number(15,3);
    
    fc number(15,3);
    
    fl number(15,3);
    
    fs number(15,3);
    

    begin

    fa := sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
    
    fb := sqrt((x0-x2)*(x0-x2)+(y0-y2)*(y0-y2));
    
    fc := sqrt((x0-x1)*(x0-x1)+(y0-y1)*(y0-y1));
    
    if fa < fRange then --当fa边长度小于警告距离时
    
      distance := fa;
    
      return 1;
    
    end if;
    
    if fb < fRange then --当fb边长度小于警告距离时
    
      distance := fb;
    
      return 1;
    
    end if;
    
    if fc < 0.01 then --当轨迹的两个坐标点重合时
    
      return 0;
    
    end if;
    

    if(fa*fa>=fb*fb+fc*fc) then –P0处角度为(钝(直)角),垂足在外

      distance := fb;
    
      return 0;
    

    end if;

    if(fb*fb>=fa*fa+fc*fc) then – P1处角度为(钝(直)角),垂足在外

      distance := fa;
    
      return 0;
    
    end if; 
    
    --利用海伦公式求垂直距离
    
    fl := (fa+fb+fc)/2;     --周长的一半    
    

    fs := sqrt(fl*(fl-fa)(fl-fb)(fl-fc)); –海伦公式求面积,也可以用矢量求

    distance := 2*fs/fc; 
    
    if distance < fRance then
    
      return 1;
    
    end if;
    
    return 0;
    

    end;

    2.4实现整个流程
    先查询得到整个预定线路的坐标,再查询出需要判断的点S,遍历整个预定线路判断S是否在整个线路的某条线段的容差范围内。

    再查询出实际线路中的第二个实际点,重复上面的过程。

    第一个过程的实现如下:

    isOutOfRanceErr := 1;

    open rs2 for select a.X,a.Y,b.X,b.Y,c.预警距离 from 坐标点表 a, 坐标点表 b, 轨迹表 c where a.轨迹ID=b.轨迹ID and a.轨迹ID = c.轨迹ID and a.坐标ID+1=b.坐标ID order by a.轨迹ID,a.坐标ID;

       loop
    
         Fetch rs2 into fP0X,fP0Y,fP1X,fP1Y,fToleRance;
    
         Exit when rs%Notfound;
    
           dummy := getNearestDistance(fP0X,fP0Y,fP1X,fP1Y,fCoordinateX,fCoordinateY,fToleRance,fDistance);
    
           if dummy = 1 then
    
              isOutOfRanceErr := 0;
    
              exit;
    
           end if;
    
         end loop;
    
       close rs2; 
    

    3.考虑方向性的算法的实现
    如果轨迹的对比还考虑方向性,即线路a-b-c-d与线路a-c-b-d是不同,其实,此时只需要用一个变量来标记每一次吻合时,数组已经对比到的地方,下次对比时应该从标记处开始后推就能实现方向性问题了。

                                                                           -----欢迎转载,但保留版权,请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/
    
    展开全文
  • 重叠I/O模型

    千次阅读 2011-06-09 16:11:00
    重叠I/O模型(1)转载来的。一. 重叠I/O的概念及使用当调用ReadFile和WriteFile时,如果最后一个参数lpOverlapped设置为NULL,那么线程就阻塞在这里,直到读写完指定的数据后,它们才返回。这样在读写大文件的时候,...

    重叠I/O模型(1)

    转载来的。

    一.              重叠I/O的概念及使用

    当调用ReadFileWriteFile时,如果最后一个参数lpOverlapped设置为NULL,那么线程就阻塞在这里,直到读写完指定的数据后,它们才返回。这样在读写大文件的时候,很多时间都浪费在等待ReadFileWriteFile的返回上面。如果ReadFileWriteFile是往管道里读写数据,那么有可能阻塞得更久,导致程序性能下降。

    为了解决这个问题,windows引进了重叠I/O的概念,它能够同时以多个线程处理多个I/O。其实你自己开多个线程也可以处理多个I/O,但是系统内部对I/O的处理在性能上有很大的优化。它是Windows下实现异步I/O最常用的方式。

    Windows为几乎全部类型的文件提供这个工具:磁盘文件、通信端口、命名管道和套接字。通常,使用ReadFileWriteFile就可以很好地执行重叠I/O

    重叠模型的核心是一个重叠数据结构。若想以重叠方式使用文件,必须用 FILE_FLAG_OVERLAPPED 标志打开它,例如:

    HANDLE hFile = CreateFile(lpFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);  

    如果没有规定该标志,则针对这个文件(句柄),重叠I/O是不可用的。如果设置了该标志,当调用ReadFileWriteFile操作这个文件(句柄)时,必须为最后一个参数提供OVERLAPPED结构:

    // WINBASE.H

    typedef struct _OVERLAPPED{

            DWORD   Internal;

            DWORD   InternalHigh;

            DWORD   Offset;

            DWORD   OffsetHigh;

            HANDLE  hEvent; //关键的一个参数

    }OVERLAPPED, *LPOVERLAPPED;

    头两个32位的结构字InternalInternalHigh由系统内部使用;其次两个32位结构字OffsetOffsetHigh使得可以设置 64位的偏移量,该偏移量是要文件中读或写的地方。

    因为I/O异步发生,就不能确定操作是否按顺序完成。因此,这里没有当前位置的概念。对于文件的操作,总是规定该偏移量。在数据流下(如COM端口或socket),没有寻找精确偏移量的方法,所以在这些情况中,系统忽略偏移量。这四个字段不应由应用程序直接进行处理或使用,OVERLAPPED结构的最后一个参数是可选的事件句柄。稍后会提到怎样使用这个参数来设定事件通知完成I/O,现在,假定该句柄是NULL

    设置了OVERLAPPED参数后,ReadFile/WriteFile的调用会立即返回,这时候你可以去做其他的事(所谓异步),系统会自动替你完成ReadFile/WriteFile相关的I/O操作。你也可以同时发出几个ReadFile/WriteFile的调用(所谓重叠)。当系统完成I/O操作时,会将OVERLAPPED.hEvent置信,我们可以通过调用WaitForSingleObject/WaitForMultipleObjects来等待这个I/O完成通知,在得到通知信号后,就可以调用GetOverlappedResult来查询I/O操作的结果,并进行相关处理。由此可以看出,OVERLAPPED结构在一个重叠I/O请求的初始化及其后续的完成之间,提供了一种沟通或通信机制

    Win32重叠I/O机制为基础,自Winsock 2发布开始,重叠I/O便已集成到新的Winsock函数中,比如WSARecv/WSASend。这样一来,重叠I/O模型便能适用于安装了Winsock 2的所有Windows平台。可以一次投递一个或多个Winsock I/O请求。针对那些提交的请求,在它们完成之后,应用程序可为它们提供服务(对I/O的数据进行处理)。

    相应的,要想在一个套接字上使用重叠I/O模型来处理网络数据通信,首先必须使用 WSA_FLAG_OVERLAPPED这个标志来创建一个套接字。如下所示:

    SOCKET s = WSASocket(AF_INET, SOCK_STEAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED);

    创建套接字的时候,假如使用的是socket函数,而非WSASocket函数,那么会默认设置WSA_FLAG_OVERLAPPED标志。成功创建好了一个套接字,将其与一个本地接口绑定到一起后,便可开始进行这个套接字上的重叠I/O操作,方法是调用下述的Winsock 2函数,同时为它们指定一个WSAOVERLAPPED结构参数(#define WSAOVERLAPPED OVERLAPPED// WINSOCK2.H):

    n         WSASend

    n         WSASendTo

    n         WSARecv

    n         WSARecvFrom

    n         WSAIoctl

    n         AcceptEx

    n         TransmitFile

    若随一个WSAOVERLAPPED结构一起调用这些函数,函数会立即返回,无论套接字是否设为锁定模式。它们依赖于WSAOVERLAPPED结构来返回一个I/O请求操作的结果

    比起阻塞、selectWSAAsyncSelect以及WSAEventSelect等模型,Winsock的重叠I/O(Overlapped I/O)模型使应用程序能达到更佳的系统性能。因为它和这4种模型不同的是,使用重叠模型的应用程序通知缓冲区收发系统直接使用数据。也就是说,如果应用程序投递了一个10KB大小的缓冲区来接收数据,且数据已经到达套接字,则该数据将直接被拷贝到投递的缓冲区。而这4种模型中,数据到达并拷贝到单套接字接收缓冲区中,此时应用程序会被系统通知可以读入的字节数。当应用程序调用接收函数之后,数据才从单套接字缓冲区拷贝到应用程序的缓冲区。这样就减少了一次从I/O缓冲区到应用程序缓冲区的拷贝,差别就在于此。

    Windows NTWindows 2000中,重叠I/O模型也允许应用程序以一种重叠方式实现对套接字连接的处理。具体的做法是在监听套接字上调用AcceptEx函数。AcceptEx是一个特殊的Winsock 1.1扩展函数,位于Mswsock.h头文件以及Mswsock.lib库文件内。该函数最初的设计宗旨是在Windows NTWindows 2000操作系统上使用Win 32的重叠I/O机制。但事实上,它也适用于Winsock 2中的重叠I/OAcceptEx的定义如下:

    // MSWSOCK.H

    AcceptEx(

           IN SOCKET sListenSocket,

           IN SOCKET sAcceptSocket,

           IN PVOID lpOutputBuffer,

           IN DWORD dwReceiveDataLength,

           IN DWORD dwLocalAddressLength,

           IN DWORD dwRemoteAddressLength,

           OUT LPDWORD lpdwBytesReceived,

           IN LPOVERLAPPED lpOverlapped);

    参数一sListenSocket参数指定的是一个监听套接字。

    参数二sAcceptSocket参数指定的是另一个套接字,负责对进入连接请求的“接受”。AcceptEx函数和accept函数的区别在于,我们必须提供接受的套接字,而不是让函数自动为我们创建。正是由于要提供套接字,所以要求我们事先调用socketWSASocket函数,创建一个套接字,以便通过sAcceptSocket参数,将其传递给AcceptEx

    参数三lpOutputBuffer参数指定的是一个特殊的缓冲区,因为它要负责三种数据的接收:服务器的本地地址,客户机的远程地址,以及在新建连接上发送的第一个数据块

    参数四dwReceiveDataLength参数以字节为单位,指定了在lpOutputBuffer缓冲区中,保留多大的空间,用于数据的接收。如这个参数设为0,那么在接受连接的过程中,不会再一道接收任何数据

    参数五dwLocalAddressLength和参数六dwRemoteAddressLength也是以字节为单位,指定在lpOutputBuffer缓冲区中,保留多大的空间,在一个套接字被接受的时候,用于本地和远程地址信息的保存。要注意的是,和当前采用的传送协议允许的最大地址长度比较起来,这里指定的缓冲区大小至少应多出16字节。举个例子来说,假定正在使用的是TCP/IP协议,那么这里的大小应设为“SOCKADDR_IN结构的长度+16字节”。

    参数七lpdwBytesReceived参数用于返回接收到的实际数据量,以字节为单位。只有在操作以同步方式完成的前提下,才会设置这个参数。假如AcceptEx函数返回ERROR_IO_PENDING,那么这个参数永远都不会设置,我们必须利用完成事件通知机制,获知实际读取的字节量

    最后一个参数是lpOverlapped,它对应的是一个OVERLAPPED结构,允许AcceptEx以一种异步方式工作。如我们早先所述,只有在一个重叠I/O应用中,该函数才需要使用事件对象通知机制hEvent字段,这是由于此时没有一个完成例程参数可供使用。

    二.获取重叠I/O操作完成结果

    当异步I/O请求挂起后,最终要知道I/O操作是否完成。一个重叠I/O请求最终完成后,应用程序要负责取回重叠I/O操作的结果。对于读,直到I/O完成,输入缓冲器才有效(参考IRP缓冲区管理)。对于写,要知道写是否成功。有几种方法可以做到这点,最直接的方法是调用(WSA)GetOverlappedResult,其函数原型如下。

    WINBASEAPI BOOL WINAPI

    GetOverlappedResult(

    HANDLE hFile,

    LPOVERLAPPED lpOverlapped,

    LPDWORD lpNumberOfBytesTransferred,

    BOOL bWait);

    WINSOCK_API_LINKAGE BOOL WSAAPI

    WSAGetOverlappedResult(

    SOCKET s,

    LPWSAOVERLAPPED lpOverlapped,                                                    

    LPDWORD lpcbTransfer,

    BOOL fWait,

    LPDWORD lpdwFlags);

    l 参数一为的文件/套接字句柄。

    l 参数二为参数一关联的(WSA)OVERLAPPED结构,在调用CreateFileWSASocketAcceptEx时指定。

    l 参数三指向字节计数指针,负责接收一次重叠发送或接收操作实际传输的字节数。

    l   参数四是确定命令是否等待的标志。Wait参数用于决定函数是否应该等待一次重叠操作完成。若将Wait设为TRUE,那么直到操作完成函数才返回;若设为FALSE,而且操作仍然处于未完成状态,那么(WSA)GetOverlappedResult函数会返回FALSE值。

     

     

    如(WSAGetOverlappedResult函数调用成功,返回值就是TRUE。这意味着我们的重叠I/O操作已成功完成,而且由参数三BytesTransfered参数指向的值已进行了更新。若返回值是FALSE,那么可能是由下述任何一种原因造成的:

    ■ 重叠I/O操作仍处在“待决”状态。

    ■ 重叠操作已经完成,但含有错误。

    ■ 重叠操作的完成状态不可判决,因为在提供给 WSAGetOverlappedResult函数的一个或多个参数中,存在着错误。

    失败后,由BytesTransfered参数指向的值不会进行更新,而且我们的应用程序应调用(WSAGetLastError函数,检查到底是何种原因造成了调用失败以使用相应容错处理。如果错误码为

    ERROR/WSA_IO_INCOMPLETE(Overlapped I/O event is not in a signaled state)

    ERROR/WSA_IO_PENDING(Overlapped I/O operation is in progress),则表明I/O仍在进行。当然,这不是真正错误,任何其他错误码则真正表明一个实际错误。

    下面介绍两种常用重叠I/O完成通知的方法。

     

    1.使用事件通知

    使用(WSAGetOverlappedResult是直截了当的,它吻合重叠I/O的概念。毕竟,如果要等待I/O,也许使用常规I/O命令更好。对于大多数程序,反复检查I/O是否完成,并非最佳。解决方案之一是使用(WSAOVERLAPPED结构中的hEvent字段,使应用程序将一个事件对象句柄同一个文件/套接字关联起来。

    当指定OVERLAPPED参数给ReadFile/WriteFileWSARecv/WSASend后,可以再为(WSA)OVERLAPPED最后一个参数提供自定义的事件对象(通过(WSA)CreateEvent创建)。

    I/O完成时,系统更改(WSA)OVERLAPPED结构对应的事件对象的传信状态,使其从“未传信”(unsignaled)变成“已传信”(signaled)。由于我们之前将事件对象分配给了(WSA)OVERLAPPED结构,所以只需简单地调用WaitForSingleObject/WaitForMultipleObjectsWSAWaitForMultipleEvents函数,从而判断出一个(一些)重叠I/O在什么时候完成。通过WaitForSingleObject/WaitForMultipleObjectsWSAWaitForMultipleEvents函数返回的索引可以知道这个重叠I/O完成事件是在哪个HANDLEFileSocket)上发生的

    然后调用(WSAGetOverlappedResult函数,将发生事件的HANDLEFileSocket)传给参数一,将这个HANDLE对应的(WSA)OVERLAPPED结构传给参数二,这样判断重叠调用到底是成功还是失败。如果返回FALSE值,则重叠操作已经完成但含有错误。或者重叠操作的完成状态不可判决,因为在提供给 WSAGetOverlappedResult函数的一个或多个参数中存在着错误。失败后,由BytesTransfered参数指向的值不会进行更新,应用程序应调用(WSA)GetLastError函数,调查到底是何种原因造成了调用失败。

    (WSAGetOverlappedResult函数返回TRUE,则根据先前调用异步I/O函数时设置的缓冲区(ReadFile/WriteFile.lpBufferWSARecv/WSASend.lpBuffers)BytesTransfered,使用指针偏移定位就可以准确操作接受到的数据了。

    利用事件对象来完成同步通知的方法比重复调用(WSA)GetOverlappedResult浪费处理器时间的方案要高效得多。

     

    2.使用完成例程

    对于文件重叠I/O操作,等待I/O操作结束的另外方法是使用ReadFileExWriteFileEx。这些命令只用于重叠I/O,当为它们的最后一个参数lpCompletionRoutine传递了一个完成例程(自定义函数)指针时,I/O操作结束时将调用此函数进行处理。

    完成例程指针LPOVERLAPPED_COMPLETION_ROUTINE定义如下:

    // WINBASE.H

    typedef  VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(

            DWORD dwErrorCode,

            DWORD dwNumberOfBytesTransfered,

            LPOVERLAPPED lpOverlapped );

    相应在Winsock 2中,WSARecv/WSASend最后一个参数lpCompletionROUTINE是一个可选的指针,它指向一个完成例程。若指定此参数(自定义函数地址),在重叠请求完成后,将调用完成例程处理。

    Winsock 2中完成例程指针LPWSAOVERLAPPED_COMPLETION_ROUTINE定义略有不同:

    // WINSOCK2.H

    typedef void (CALLBACK * LPWSAOVERLAPPED_COMPLETION_ROUTINE)(

            DWORD dwError,

            DWORD cbTransferred,

            LPWSAOVERLAPPED lpOverlapped,

            DWORD dwFlags );

         前三个参数同LPOVERLAPPED_COMPLETION_ROUTINE,参数四一般不用,置0用完成例程完成一个重叠I/O请求之后,参数中会包含下述信息:

    参数一dwError表明了一个重叠操作(由lpOverlapped指定)的完成状态是什么。

    参数二BytesTransferred参数指定了在重叠操作实际传输的字节量是多大。

    参数三lpOverlapped参数指定的是调用这个完成例程的异步I/O操作函数(ReadFileEx/WriteFileExWSARecv/WSASend)(WSA)OVERLAPPED结构参数。

    用一个完成例程提交的重叠I/O请求时,(WSA)OVERLAPPED结构的事件字段hEvent并未使用。也就是说,我们不可将一个事件对象同重叠I/O请求关联到一起。使用一个含有完成例程指针参数的异步I/O函数发出一个重叠I/O请求之后,一旦重叠I/O操作完成,作为我们的调用线程,必须能够通知完成例程指针所指向的自定义函数开始执行,提供数据处理服务。这样一来,便要求将调用线程置于一种“可警告的等待状态”,在I/O操作完成后,自动调用完成例程加以处理。WSAWaitForMultipleEvents函数可用来将线程置于一种可警告的等待状态。这样做的代价是必须创建一个事件对象可用于WSAWaitForMultipleEvents函数。假定应用程序只用完成例程对重叠请求进行处理,便不可能有任何事件对象需要处理。作为一种变通方法,我们的应用程序可用Win32SleepEx函数将自己的线程置为一种可警告等待状态。当然,亦可创建一个伪事件对象,不将它与任何东西关联在一起。假如调用线程经常处于繁忙状态,而且并不处在一种可警告的等待状态,那么完成例程根本不会得到调用。

    如前面所述,WSAWaitForMultipleEvents通常会等待同WSAOVERLAPPED结构关联在一起的事件对象。该函数也可用于将我们的线程设计成一种可警告等待状态,并可为已经完成的重叠I/O请求调用完成例程进行处理(前提是将fAlertable参数设为TRUE)。使用一个含有完成例程指针的异步I/O函数提交了重叠I/O请求之后,WSAWaitForMultipleEvents的返回值是WAIT_IO_COMPLETIONOne or more I/O completion routines are queued for execution),而不是事件数组中的一个事件对象索引。从宏WAIT_IO_COMPLETION的注解可知,它的意思是有完成例程需要执行。SleepEx函数的行为实际上和WSAWaitForMultipleEvents差不多,只是它不需要任何事件对象。对SleepEx函数的定义如下:

    WINBASEAPI DWORD WINAPI

    SleepEx(

        DWORD dwMilliseconds,

        BOOL bAlertable );

    其中,dwMilliseconds参数定义了SleepEx函数的等待时间,以毫秒为单位。假如将dwMilliseconds设为INFINITE,那么SleepEx会无休止地等待下去。bAlertable参数规定了一个完成例程的执行方式,若将它设置为FALSE,则使用一个含有完成例程指针的异步I/O函数提交了重叠I/O请求后,I/O完成例程不会执行,而且SleepEx函数不会返回,除非超过由dwMilliseconds规定的时间;若将它设置为TRUE,则完成例程会得到执行,同时SleepEx函数返回WAIT_IO_COMPLETION

    利用完成例程处理重叠I/O的Winsock程序的编写步骤如下:

    1) 新建一个监听套接字,在指定端口上监听客户端的连接请求。

    2) 接受一个客户端的连接请求,并返回一个会话套接字负责与客户端通信。

    3) 为会话套接字关联一个WSAOVERLAPPED结构。

    4) 在套接字上投递一个异步WSARecv请求,方法是将WSAOVERLAPPED指定成为参数,同时提供一个完成例程。

    5) 在将fAlertable参数设为TRUE的前提下,调用WSAWaitForMultipleEvents,并等待一个重叠I/O请求完成。重叠请求完成后,完成例程会自动执行,而且WSAWaitForMultipleEvents会返回一个WAIT_IO_COMPLETION。在完成例程内,可随一个完成例程一道投递另一个重叠WSARecv请求。

    6) 检查WSAWaitForMultipleEvents是否返回WAIT_IO_COMPLETION

    7) 重复步骤5 )6 )

    当调用accept处理连接时,一般创建一个AcceptEvent伪事件,当有客户连接时,需要手动SetEvent(AcceptEvent);当调用AcceptEx处理重叠的连接时,一般为ListenSocket创建一个ListenOverlapped结构,并为其指定一个伪事件,当有客户连接时,系统自动将其置信。这些伪事件的作用在于,当含有完成例程指针的异步I/O操作(WSARecv)完成时,设置了fAlertableWSAWaitForMultipleEvents返回WAIT_IO_COMPLETION,并调用完成例程指针指向的完成例程对数据进行处理。

    重叠I/O模型的缺点是它为每一个I/O请求都开了一个线程,当同时有成千上万个请求发生时,系统处理线程上下文切换是非常耗时的。所以这也就引出了更为先进的完成端口模型IOCP,用线程池来解决这个问题。

    展开全文
  • 重叠I/O详解

    千次阅读 2015-11-10 11:38:26
    在windows中有一个api叫readfile     bool readfile(   handle hfile, // handle to file   lpvoid lpbuffer, // data buffer
  • 实现ImageView中两张图片重叠显示

    万次阅读 2013-10-19 10:09:47
    第一种XML配置 使用layer-list标签 然后设置 image.setImageDrawable(getResources().getDrawable(R.layout.layer)); 第二种代码生成 Resources r = getResources();...Drawable[] layers = new Drawable
  • 重叠相加法&重叠保留法

    万次阅读 多人点赞 2018-08-26 13:38:47
    1.问题 上一篇中介绍了利用循环卷积计算线性卷积,但是当两个卷积项长度相差很大时,短序列需要补的0非常多,这样无助于计算量的减小,并且这种方法需要等长序列全部输入完之后才开始计算,这会造成输出有很大的...
  • 文件重叠操作

    2017-11-23 01:12:30
    示例中分别使用了重叠结构与非重叠结构操作文件,你可以根据实际中的需求自己取舍。
  • leetcode 重叠区间问题

    千次阅读 2019-05-07 00:38:24
    重叠区间问题可以总结为在坐标轴上若干个位置为 (start(i),end(i))的区间,要求求解这些区间中有多少个不重叠区间,或者合并重叠的区间。 leetcode有大神总结了通用模板,点这里 该问题分两类:第一类求重叠区间个...
  • 用\n这个只能隔一行。。不能隔两三行的? ![图片说明](https://img-ask.csdn.net/upload/201703/29/1490757276_640219.png)
  • echarts中饼图标签重叠的解决方案

    万次阅读 2019-10-23 10:30:00
    avoidLabelOverlap:是否启用防止标签重叠策略,默认开启,在标签拥挤重叠的情况下会挪动各个标签的位置,防止标签间的重叠。 当avoidLabelOverlap设置为false时会出现以下情况 改为true之后就不会重叠 代码...
  • css布局两张图片重叠

    万次阅读 2013-06-28 15:28:30
    最外层用relative,里面用absoulte
  • 两个div重叠显示

    千次阅读 2018-10-19 21:06:25
    想要将兄弟div元素进行重叠 将父元素position设置为relative,子元素position设置为absolute 使用z-index设置谁显示在上层、谁显示在下层
  • CSS 外边距(margin)重叠及防止方法

    万次阅读 2016-03-01 16:43:20
    两个或多个块级盒子的垂直相邻边界会重合。结果的边界宽度是相邻边界宽度...但是边界的重叠也有例外情况: 1、水平边距永远不会重合。 2、在规范文档中,2个或以上的块级盒模型相邻的垂直margin会重叠。最终的margi
  • div边框重叠 解决办法

    万次阅读 2017-06-13 14:36:24
    解决办法:设置边框的相反数,比如边框为1PX, 则给每块的div添加margin-right:-1px; margin-bottom:-1px.
  • css文字重叠解决

    万次阅读 2016-10-12 15:08:23
    DIV+CSS布局文字较多时候重叠下一行文字内容如何解决? 出现原因是因为对li设置了css高度和宽度,当内容比较多是内容会自动换行,而又有高度,这样就造成内容溢出而与下一排内容重叠覆盖现象。解决方法如下: 第...
  • echarts饼图文字重叠问题

    万次阅读 2016-11-26 19:50:17
    主要是不要设置position属性,默认就行了。 series:{ itemStyle:{ normal:{ label:{ // postion:'innner' } } } }
  • 上午win7在系统补丁自动更新后,
  • Altiumdesigenr中如何允许两个元件重叠

    千次阅读 2018-11-06 12:27:30
    取消勾选就行了
  • margin重叠 及防止方法

    万次阅读 2018-10-22 10:26:30
    注:本文转载自(http://www.hujuntao.com/web/css/css-margin-overlap.html) 前段时间辞职了,然后一直处于求职的状态,面试的第一家公司是一家初创公司,在...今天先就里面的一个问题-mar...
1 2 3 4 5 ... 20
收藏数 254,227
精华内容 101,690
关键字:

重叠