none
串口通讯用api函数,数据收发不全 RRS feed

  • 问题

  • 在应用中,采用异步的方式进行串口数据的收发,在silicon lab的usb转串口芯片上出现了,readfile返回值为true,但获取的 实际字节数与缓冲区可用字节数不等,由于范围为true,根据msdn的手册,就未执行GetOverlappedResult,通用通讯底层,在其他串口上未出现该现象,完整代码如下。请问导致该问题的原因是什么?
    
    //---------------------------------------------------------------------------


    #pragma hdrstop

    #include "SerialPortEx.h"
    #include <stdio.h>
    #include <string>
    #include "MessageDefine.h"
    #include "DebugFile.h"
    #include "UserConfig.hpp"
    using namespace std;

    //---------------------------------------------------------------------------

    #pragma package(smart_init)

    __fastcall CSerialPortEx::CSerialPortEx(TComponent* AOwner, bool msgEnable)
            :CAbstractDevice(AOwner, msgEnable)
    {
            m_hSerialPort = NULL;
            if (m_overlappedRead.hEvent != NULL)                                        //m_overlapped.hEvent 事件内核对象    对文件的读写请求
                    ResetEvent(m_overlappedRead.hEvent);
             m_overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);              //overlapped 成员 hEvent必须设置TRUE 手动重置

            if (m_overlappedWrite.hEvent != NULL)                                        //m_overlapped.hEvent 事件内核对象    对文件的读写请求
                    ResetEvent(m_overlappedWrite.hEvent);
             m_overlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);              //overlapped 成员 hEvent必须设置TRUE 手动重置
             if (m_hShutdownEvent != NULL)
                      ResetEvent(m_hShutdownEvent);
             m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);                //退出串口事件  手动重置

             // initialize the event objects
             m_hEventArray[0] = m_hShutdownEvent;         // highest priority     最高优先级
             m_hEventArray[1] = m_overlappedRead.hEvent;

             // m_Critical作为是否要进临界区的标记, m_waitInterval 配置读的等待间隔
             //  m_waitInterval < 200 时,发生读取数据不全的概率较大
             m_Critical = GetSerialInterVal(m_waitInterval);
    }

    __fastcall CSerialPortEx::~CSerialPortEx()
    {
            if(m_overlappedRead.hEvent)
            {
                    ResetEvent(m_overlappedRead.hEvent);
                    m_overlappedRead.hEvent = NULL;
            }
            if(m_overlappedWrite.hEvent)
            {
                    ResetEvent(m_overlappedWrite.hEvent);
                    m_overlappedWrite.hEvent = NULL;
            }
            if(m_hShutdownEvent)
            {
                    ResetEvent(m_hShutdownEvent);
                    m_hShutdownEvent = NULL;
            }
    }

    bool CSerialPortEx::IsOpen()
    {
    //        return m_SerialPort.IsOpen();
            if(m_hSerialPort == INVALID_HANDLE_VALUE)
                    return false;
            else
                    return m_hSerialPort != NULL;
    }

    bool CSerialPortEx::Close()
    {
            BOOL res;
            if(IsOpen())
            {
                    SetEvent(m_hShutdownEvent);
                    Sleep(1);
                    res = CloseHandle(m_hSerialPort);
                    g_debugFile.AddText("关闭串口:"+IntToStr(m_nPort)+"  !");
                    if(res)
                            m_hSerialPort = NULL;
                    return res;
            }
            else
                    return TRUE;
    }

    bool CSerialPortEx::Open()
    {
            try
            {
                    if(IsOpen())
                    {
                            return TRUE;
                    }

                    if(initPort(this,m_nPort,m_nBaud,m_chParity,m_nDataBits,m_nStopsBits,
                            EV_RXCHAR | EV_CTS))
                    {
                            g_debugFile.AddText("打开串口:"+IntToStr(m_nPort)+"  成功!");
                            return true;
                    }
                    else
                    {
                            g_debugFile.AddText("打开串口:"+IntToStr(m_nPort)+"  失败!");
                            return false;
                    }
            }
            catch(char* err)
            {
                    g_debugFile.AddText("打开串口:"+IntToStr(m_nPort)+"  异常!");
                    return false;
            }
    }

    void CSerialPortEx::SetDeviceProperties(const char* szProperties)
    {
            string strProperties(szProperties);
            int nIndex = strProperties.find_first_of(',');
            string strPort = strProperties.substr(0,nIndex);
            strProperties = strProperties.substr(nIndex + 1);

            nIndex = strProperties.find_first_of(',');
            string strBaud = strProperties.substr(0,nIndex);
            strProperties = strProperties.substr(nIndex + 1);

            nIndex = strProperties.find_first_of(',');
            string strParity = strProperties.substr(0,nIndex);
            strProperties = strProperties.substr(nIndex + 1);

            nIndex = strProperties.find_first_of(',');
            string strDataBits = strProperties.substr(0,nIndex);
            strProperties = strProperties.substr(nIndex + 1);

            nIndex = strProperties.find_first_of(',');
            string strStopBits = strProperties.substr(0,nIndex);
            strProperties = strProperties.substr(nIndex + 1);

            nIndex = strProperties.find_first_of(',');
            string strSndBufferSize = strProperties.substr(0,nIndex);
            strProperties = strProperties.substr(nIndex + 1);

            nIndex = strProperties.find_first_of(',');
            string strRcvBufferSize = strProperties.substr(0,nIndex);
            strProperties = strProperties.substr(nIndex + 1);

            m_nPort = atoi(strPort.c_str());
            m_nBaud = atoi(strBaud.c_str());
            m_chParity = strParity[0];
            m_nDataBits = atoi(strDataBits.c_str());
            m_nStopsBits = atoi(strStopBits.c_str());
            m_nSndBufferSize = atoi(strSndBufferSize.c_str());
            m_nRcvBufferSize = atoi(strRcvBufferSize.c_str());

            if(IsOpen())
            {
                    Close();
                    Sleep(100);
                    Open();
            }
    }

    void CSerialPortEx::Send(const BYTE* pBuffer, const DWORD nSize)
    {
            if(m_Critical)
            {
                    EnterCriticalSection(m_pCriticalSection_Snd);
                    m_dwSendSize = nSize;
                    memset(m_szSendBuffer, 0, m_dwSendSize);
                    memcpy(m_szSendBuffer,pBuffer,m_dwSendSize);
                    send();
                    LeaveCriticalSection(m_pCriticalSection_Snd);
            }
            else
            {
                    m_dwSendSize = nSize;
                    memset(m_szSendBuffer, 0, m_dwSendSize);
                    memcpy(m_szSendBuffer,pBuffer,m_dwSendSize);
                    send();
            }
    }

    void CSerialPortEx::Receive(BYTE*& pBuffer, int& nSize)
    {

    }

     //---------------------------------------------------------------------------
    //--打开串口
    //--------------------------------------------------------------------------
    BOOL CSerialPortEx::initPort(HANDLE hMsgRcver, unsigned long dwPortnr, unsigned long dwBaud,
                    char cParity, unsigned long dwDatabits, unsigned long dwStopbits,
                    unsigned long dwCommEvents)
    {
            char szPort[20] = {0};
            char szBaud[100] = {0};
            sprintf(szPort, "\\\\.\\COM%d", dwPortnr);
            sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", dwBaud, cParity,
                    dwDatabits, dwStopbits);
            ResetEvent(m_hShutdownEvent);
            ResetEvent(m_overlappedRead.hEvent);
            ResetEvent(m_overlappedWrite.hEvent);

            m_hSerialPort = CreateFile(szPort,                                            // communication port string (COMX)
                   GENERIC_READ | GENERIC_WRITE,                                         // read/write types
                   0,                                                                        // comm devices must be opened with exclusive access
                   NULL,                                                                       // no security attributes
                   OPEN_EXISTING,                                                             // comm devices must use OPEN_EXISTING
                   FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,                           // Async I/O
                   0);                                                                       // template must be 0 for comm devices
            if(m_hSerialPort == INVALID_HANDLE_VALUE)
                    return FALSE;
            // set the timeout values
             m_commTimeouts.ReadIntervalTimeout = 1000;
             m_commTimeouts.ReadTotalTimeoutMultiplier = 1000;
             m_commTimeouts.ReadTotalTimeoutConstant = 1000;
             m_commTimeouts.WriteTotalTimeoutMultiplier = 1000;
             m_commTimeouts.WriteTotalTimeoutConstant = 1000;

            m_overlappedRead.Offset = 0;
            m_overlappedRead.OffsetHigh = 0;
            m_overlappedWrite.Offset = 0;
            m_overlappedWrite.OffsetHigh = 0;

            if(!SetupComm(m_hSerialPort, DEVICE_SNDBUF_SIZE, DEVICE_RCVBUF_SIZE))   //设置串口
            {
                    tackleError("SetupComm Error.");
                    return FALSE;
            }

            if(!SetCommTimeouts(m_hSerialPort, &m_commTimeouts))                     //设置串口超时事件
            {
                    tackleError("SetCommTimeouts Error.");
                    return FALSE;
            }

            if(!SetCommMask(m_hSerialPort,dwCommEvents))                            //设置串口?触发事件??
            {
                    tackleError("SetCommMask Error.");
                    return FALSE;
            }

            if(!GetCommState(m_hSerialPort, &m_dcb))                                //获取串口设备状态???
            {
                    tackleError("GetCommState Error.");
                    return FALSE;
            }

            m_dcb.fRtsControl = RTS_CONTROL_ENABLE;                                          // set RTS bit high!
            if(!BuildCommDCB(szBaud, &m_dcb))
            {
                    tackleError("BuildCommDCB Error.");
                    return FALSE;
            }

            if(!SetCommState(m_hSerialPort, &m_dcb))
            {
                    tackleError("SetCommState Error.");
                    return FALSE;
            }

            PurgeComm(m_hSerialPort, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
            return TRUE;
    }
     //---------------------------------------------------------------------------
    //--处理错误信息  主要用于打开串口时返回各种错误信息,并关闭串口
    //--------------------------------------------------------------------------
    void CSerialPortEx::tackleError(const char* szError)
    {
            processErrorMessage(szError);
            CloseHandle(m_hSerialPort);
            m_hSerialPort = NULL;
    }
     //---------------------------------------------------------------------------
    //--接收线程
    //--------------------------------------------------------------------------
    void CSerialPortEx::threadProc_Rcv(BOOL* pbRunSignal, CRITICAL_SECTION* pCriticalSection,
            void* arg)
    {
            unsigned long dwEvent;
            unsigned long dwCommEvent;
            unsigned long dwError;
            BOOL bResult;  
            try
            {
                 if(m_hSerialPort)
                          PurgeComm(m_hSerialPort, PURGE_RXCLEAR | PURGE_RXABORT);
          //                PurgeComm(m_hSerialPort, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
                  while(*pbRunSignal)
                  {     
                          bResult = WaitCommEvent(m_hSerialPort, &dwEvent, &m_overlappedRead);    //等待串口的异步事件的激活
                          if(bResult)                                                      //清除错误
                          {
                                  bResult = ClearCommError(m_hSerialPort, &dwError, &m_comstat);
                                  if (m_comstat.cbInQue == 0)
                                          continue;
                          }
                          else
                          {
                                  switch (dwError = GetLastError())
                                  {
                                  case ERROR_IO_PENDING:
                                                  break;
                                  case 87:
                                                  break;
                                  default:
                                                  processErrorMessage("WaitCommEvent Error.");
                                                  break;
                                  }
                          }
                          //   m_waitInterval < 200 时,发生读取数据不全的概率较大
                          // 请说明 m_waitInterval 的间隔有何限制,主要是读的丢数的问题
                          dwEvent = WaitForMultipleObjects(2, m_hEventArray, FALSE, m_waitInterval);  //判断是何种事件发送
                          switch(dwEvent)
                          {
                          case 0: 
                                  ResetEvent(m_hShutdownEvent);                           //设置关闭事件处于非触发状态
                                  return;
                          case 1:
                                  {
                                          GetCommMask(m_hSerialPort, &dwCommEvent);       //获取串口当前触发事件
                                          if (dwCommEvent & EV_RXCHAR)
                                          {
                                                  receive(*pbRunSignal);
                                          }
                                          break;
                                  }
                          }
                  }
            }
            catch(char* err)
            {
                    g_debugFile.AddText("Serial接收线程处理异常!");
                    return ;
            }
    }

    void CSerialPortEx::threadProc_Snd(BOOL* pbRunSignal, CRITICAL_SECTION* pCriticalSection, void* arg)
    {

    }
     //---------------------------------------------------------------------------
    //--接收到信息处理   事件激发 则进行数据的接收 ,否则退出
    //--------------------------------------------------------------------------
    void CSerialPortEx::receive(BOOL bRunSignal)
    {
            if(!bRunSignal)                                                        //在关闭程序时有可能会先执行析构函数释放缓冲区,如果此时
                    return;                                                         //接收线程仍未停止,访问被释放的缓冲区会造成崩溃
                    
             BOOL  bRead = TRUE;
             BOOL  bResult = TRUE;
             DWORD dwError = 0;
            int readSize = 0;
            try
            {
                    while(1)
                    {
                            EnterCriticalSection(m_pCriticalSection_Rcv);
                            bResult = ClearCommError(m_hSerialPort, &dwError, &m_comstat);
                            LeaveCriticalSection(m_pCriticalSection_Rcv);

                            if (m_comstat.cbInQue == 0)
                            {
                                    // break out when all bytes have been read
                                    break;
                            }
                            //进入读取数据的临界区,进行数据的读取
                            EnterCriticalSection(m_pCriticalSection_Rcv);

                            if (bRead)
                            {
                                    bResult = ReadFile(m_hSerialPort,                          // Handle to COMM port
                                                       m_szReceiveBuffer,                   // RX Buffer Pointer
                                                       m_comstat.cbInQue,                          // Read all bytes
                                                       &m_dwReceiveSize,                          // Stores number of bytes read
                                                       &m_overlappedRead);                          // pointer to the m_ov structure

                                    //log 记录读取状态
                                    g_debugFile.ShowBuf("in ReadFile flag ="+BoolToStr(bResult)+ ", m_comstat.cbInQue = " +
                                         IntToStr(m_comstat.cbInQue) + "m_dwReceiveSize = "  +IntToStr(m_dwReceiveSize) +"\n",
                                        (BYTE*)m_szReceiveBuffer, m_dwReceiveSize);
                                    // deal with the error code
                                    if (!bResult)
                                    { 
                                            switch (dwError = GetLastError())
                                            { 
                                            case ERROR_IO_PENDING:
                                                    {
                                                            // asynchronous i/o is still in progress
                                                            // Proceed on to GetOverlappedResults();
                                                            processErrorMessage("ReadFile ERROR_IO_PENDING.");
                                                            bRead = FALSE;
                                                            break;
                                                    }
                                            default:
                                                    {
                                                            // Another error has occured.  Process this error.
                                                            processErrorMessage("ReadFile Error.");
                                                            break;
                                                    }
                                            }
                                    }
                                    else
                                    {
                                            // ReadFile() returned complete. It is not necessary to call GetOverlappedResults()
                                            if(m_dwReceiveSize != m_comstat.cbInQue)
                                            {
                                                  bRead = false;
                                                  // log 记录 读取字节不全,信号超时受信
                                                  // 请说明 什么情况下,会导致读取字节不全 m_dwReceiveSize != m_comstat.cbInQue的原因
                                                  g_debugFile.AddText("读取字节不全,信号超时受信 ReadFile flag ="+BoolToStr(bResult)+ ", m_comstat.cbInQue = " +
                                                          IntToStr(m_comstat.cbInQue) + "m_dwReceiveSize = "  +IntToStr(m_dwReceiveSize));
                                            }
                                            else
                                            {
                                                  bRead = TRUE;
                                            }
                                    }
                            }  // close if (bRead)

                            if (!bRead)
                            {
                                    g_debugFile.AddText("in GetOverlappedResults() in ReadFile()");
                                    bRead = TRUE;
                                    bResult = GetOverlappedResult(m_hSerialPort,         // Handle to COMM port
                                                                  &m_overlappedRead,                  // Overlapped structure
                                                                  &m_dwReceiveSize,                  // Stores number of bytes read
                                                                  TRUE);                            // Wait flag
                                    // deal with the error code
                                    if (!bResult)
                                    {
                                            processErrorMessage("GetOverlappedResults() in ReadFile()");
                                    }
                            }  // close if (!bRead)
                             // log 记录接收到的数据,并进行进行数据的接收处理
                            g_debugFile.ShowBuf( "串口接收数据 m_dwReceiveSize= " +IntToStr(m_dwReceiveSize) +"\n",
                            (BYTE*)m_szReceiveBuffer, m_dwReceiveSize);
                            if(fpRcvFunctionProc)
                                    (*fpRcvFunctionProc)(m_pParent, m_szReceiveBuffer, m_dwReceiveSize);
                            LeaveCriticalSection(m_pCriticalSection_Rcv);
                    }
            }
            catch(char* err)
            {
                    g_debugFile.AddText("Serial数据的接收处理调用异常!");
                    return ;
            }
    }
     //---------------------------------------------------------------------------
    //--发送数据到串口
    //--------------------------------------------------------------------------
    void CSerialPortEx::send()
    {
            g_debugFile.AddText("in CSerialPortEx::send()");
            if(m_dwSendSize < 1)
                    return;

             BOOL bResult = TRUE;
             BOOL  bSend = TRUE;
             unsigned long dwBytesSent = 0;
             // Gain ownership of the critical section
             EnterCriticalSection(m_pCriticalSection_Snd);
             // Initailize variables
            m_overlappedWrite.Offset = 0;
            m_overlappedWrite.OffsetHigh = 0;

            // PurgeComm
            // Clear buffer
            // 请说明 PurgeComm 的间隔有何限制,主要是写的丢数的问题
            PurgeComm(m_hSerialPort, PURGE_TXCLEAR | PURGE_TXABORT);

            bResult = WriteFile(m_hSerialPort,                                    // Handle to COMM Port
                                m_szSendBuffer,                                    // Pointer to message buffer in calling finction
                                m_dwSendSize,                                 // Length of message to send
                                &dwBytesSent,                                    // Where to store the number of bytes sent
                                &m_overlappedWrite);                                    // Overlapped structure

             // deal with any error codes
            if (!bResult)
            {
                    unsigned long dwError = GetLastError();
                    switch (dwError)
                    {
                    case ERROR_IO_PENDING:                                   //串口正在进行读写操作
                            {
                                    // continue to GetOverlappedResults()
                                    dwBytesSent = 0;
                                    g_debugFile.AddText("WriteFile ERROR_IO_PENDING ");
                                    bResult = GetOverlappedResult(m_hSerialPort,         // Handle to COMM port
                                                &m_overlappedWrite,                  // Overlapped structure
                                                &dwBytesSent,                  // Stores number of bytes sent
                                                TRUE);                            // Wait flag

                                    LeaveCriticalSection(m_pCriticalSection_Snd);

                                    // deal with the error code   等待操作完成,仍失败
                                    if (!bResult)
                                    {
                                            bSend = false;
                                            processErrorMessage("GetOverlappedResults() in WriteFile()");
                                    }
                                    break;
                            }
                    default:
                            {
                                    // all other error codes
                                    LeaveCriticalSection(m_pCriticalSection_Snd);
                                    processErrorMessage("WriteFile() Error.");
                                    bSend = false;
                            }
                    }
            }
            else
            {
                    LeaveCriticalSection(m_pCriticalSection_Snd);
            }
            g_debugFile.AddText("out CSerialPortEx::send()");
            return;
    }

        
    
    

    2017年6月26日 23:36

全部回复

  • Hi tongniuniu,

    感谢在MSDN论坛发帖。

    >>在应用中,采用异步的方式进行串口数据的收发,在silicon lab的usb转串口芯片上出现了,readfile返回值为true,但获取的 实际字节数与缓冲区可用字节数不等,由于范围为true,根据msdn的手册,就未执行GetOverlappedResult,通用通讯底层,在其他串口上未出现该现象,完整代码如下。请问导致该问题的原因是什么?

    ReadFile函数返回true并不能说明字节已经完全读取。当你使用FILE_FLAG_OVERLAPPED打开hFile时,你需要注意以下几点:

    1. lpOverlapped参数必须指向有效且唯一的OVERLAPPED结构,否则该函数可能会错误地报告读操作完成。
    2. lpNumberOfBytesRead参数应设置为NULL。使用GetOverlappedResult函数来获取实际读取的字节数。如果hFile参数与I / O完成端口相关联,您还可以通过调用GetQueuedCompletionStatus函数获取读取的字节数。

    希望对你有所帮助。

    Best Regards,
    Sera Yu


    MSDN Community Support<br/> Please remember to click &quot;Mark as Answer&quot; the responses that resolved your issue, and to click &quot;Unmark as Answer&quot; if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact <a href="mailto:MSDNFSF@microsoft.com">MSDNFSF@microsoft.com</a>.

    2017年6月27日 8:02
  • 谢谢你的耐心回答,先前对api函数的理解太肤浅了,看了Readfile的返回结果为true以为就是,读成功了,经过你的指点,我正在消化,ReadFile 与 GetOverlappedResult函数,你说的第一个问题,我是这样做的,第二个我还要去尝试下,另外,发现ReadFile里有讲一个例子“” Asynchronous Disk I/O Appears as Synchronous on Windows“这个我还没有看完,等我看完了,有问题再问你,再次感谢你的回答

    》》ReadFile函数返回true并不能说明字节已经完全读取。当你使用FILE_FLAG_OVERLAPPED打开hFile时,你需要注意以下几点:

    1. lpOverlapped参数必须指向有效且唯一的overlapped结构,否则该函数可能会错误地报告读操作完成。
    2. lpNumberOfBytesRead参数应设置为NULL。使用 GetOverlappedResult函数来获取实际读取的字节数。如果hFile参数与I / O完成端口相关联,您还可以通过调用GetQueuedCompletionStatus函数获取读取的字节数。

    希望对你有所帮助。

    2017年6月28日 15:26
  • 今天,我大致看完了msdn中readfile和GetOverlappedResult的内容,以及Asynchronous Disk I/O Appears as Synchronous on Windows;这里面的进行异步读文件的,还有以下几个疑问
    1.GetOverlappedResult例子中判断readfile的返回结果是否为真,如果为真了,其判断为异步操作同步做完了,里面的注释我也是不太理解,是否是说大部分文件系统在第一次读取之后,会触发同步都操作?是怎么理解的?
    2.我是在串口通讯中,用的异步的readfile的返回结果, 后面“Asynchronous Disk I/O Appears as Synchronous on Windows”一文里说,“For a disk device, typically, an I/O request can be completed "immediately" when the data is cached in memory.”,请问此时读取的字节数不可信,为何例子中还时在realdfile成功后,不用GetOverlappedResult重新获取实际字节数

    3.如果收到字符后,同步完成读操作,这会的实际读取的字节为何不等于实际缓冲区的数据?
    4.推荐的异步读取应该如何写
    5.你的建议2里面的第2条,实际读取字节地址为何建议为空,这是为了Readfile肯定是异步完成还是其他原因?

    文中部分代码

       if (!ReadFile(hFile,
                     pDataBuf,
                     dwSizeOfBuffer,
                     &NumberOfBytesRead,
                     &osReadOperation )
       {
          if (GetLastError() != ERROR_IO_PENDING)
          {
             // Some other error occurred while reading the file.
             ErrorReadingFile();
             ExitProcess(0);
          }
          else
             // Operation has been queued and
             // will complete in the future.
             fOverlapped = TRUE;
       }
       else
          // Operation has completed immediately.
          fOverlapped = FALSE;
    
       if (fOverlapped)
       {
          // Wait for the operation to complete before continuing.
          // You could do some background work if you wanted to.
          if (GetOverlappedResult( hFile,
                                   &osReadOperation,
                                   &NumberOfBytesTransferred,
                                   TRUE))
             ReadHasCompleted(NumberOfBytesTransferred);
          else
             // Operation has completed, but it failed.
             ErrorReadingFile();
       }
       else
          ReadHasCompleted(NumberOfBytesRead);


    2017年6月29日 14:34
  • 前几天,我在论坛提了,我用异步读取串口时,出现ReadFile读出的字节数与实际字节数不一致,经Sera Yu 指导,我大致看完了msdn中readfile和GetOverlappedResult的内容,以及Asynchronous Disk I/O Appears as Synchronous on Windows;这里面的进行异步读文件的,有以下几个疑问
    1.GetOverlappedResult例子中判断readfile的返回结果是否为真,如果为真了,其判断为异步操作同步做完了,里面的注释我也是不太理解,是否是说大部分文件系统在第一次读取之后,会触发同步都操作?是怎么理解的?
    2.我是在串口通讯中,用的异步的readfile的返回结果, 后面“Asynchronous Disk I/O Appears as Synchronous on Windows”一文里说,“For a disk device, typically, an I/O request can be completed "immediately" when the data is cached in memory.”,请问此时读取的字节数不可信,为何例子中还时在realdfile成功后,不用GetOverlappedResult重新获取实际字节数

    3.如果收到字符后,同步完成读操作,这会的实际读取的字节为何不等于实际缓冲区的数据?
    4.推荐的异步读取应该如何写
    5.异步读取时,建议实际读取字节地址为何建议为空,这是为了Readfile肯定是异步完成还是其他原因?

    文中部分代码

       if (!ReadFile(hFile,
                     pDataBuf,
                     dwSizeOfBuffer,
                     &NumberOfBytesRead,
                     &osReadOperation )
       {
          if (GetLastError() != ERROR_IO_PENDING)
          {
             // Some other error occurred while reading the file.
             ErrorReadingFile();
             ExitProcess(0);
          }
          else
             // Operation has been queued and
             // will complete in the future.
             fOverlapped = TRUE;
       }
       else
          // Operation has completed immediately.
          fOverlapped = FALSE;
    
       if (fOverlapped)
       {
          // Wait for the operation to complete before continuing.
          // You could do some background work if you wanted to.
          if (GetOverlappedResult( hFile,
                                   &osReadOperation,
                                   &NumberOfBytesTransferred,
                                   TRUE))
             ReadHasCompleted(NumberOfBytesTransferred);
          else
             // Operation has completed, but it failed.
             ErrorReadingFile();
       }
       else
          ReadHasCompleted(NumberOfBytesRead);


    • 已编辑 tongniuniu 2017年7月2日 13:53
    • 已合并 Baron Bi 2017年7月20日 3:02 same case
    2017年7月2日 13:51
  • Hi,

    >>1.GetOverlappedResult例子中判断readfile的返回结果是否为真,如果为真了,其判断为异步操作同步做完了,里面的注释我也是不太理解,是否是说大部分文件系统在第一次读取之后,会触发同步都操作?是怎么理解的?

    你具体指的哪段注释,请详细说明一下。
    >>2.我是在串口通讯中,用的异步的readfile的返回结果, 后面“Asynchronous Disk I/O Appears as Synchronous on Windows”一文里说,“For a disk device, typically, an I/O request can be completed "immediately" when the data is cached in memory.”,请问此时读取的字节数不可信,为何例子中还时在realdfile成功后,不用GetOverlappedResult重新获取实际字节数

    大多数I / O驱动程序(磁盘,通信和其他)都有特殊的代码,如果I / O请求可以“立即完成”,这个时候操作已经完成,ReadFile或WriteFile函数将返回TRUE,形成类似同步操作的现象。所以不需要GetOverlappedResult再检测了。但是通常情况下,并不建议你这么做。建议你使用FILE_FLAG_NO_BUFFERING标志,它指示文件系统根本不使用任何缓存机制。这可以确保I / O请求实际上是真实的异步操作。
    >>3.如果收到字符后,同步完成读操作,这会的实际读取的字节为何不等于实际缓冲区的数据?

    当你使用同步操作时,系统会做以下操作。

    如果lpOverlapped为NULL,则读取操作从当前文件位置开始,并且ReadFile不会返回,直到操作完成,并且系统在ReadFile返回之前更新文件指针。如果lpOverlapped不为NULL,则读取操作从OVERLAPPED结构中指定的偏移开始,并且ReadFile在读操作完成之前不返回。 在ReadFile返回之前,系统会更新OVERLAPPED偏移量。当同步读取操作到达文件的末尾时,ReadFile返回TRUE,并将* lpNumberOfBytesRead设置为零。

    更多关于异步和同步的操作,可以参考以下文档。

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx

    >>4.推荐的异步读取应该如何写

    这里有篇示例,你可以参考一下。

    https://code.msdn.microsoft.com/windowsdesktop/CppAsynchronousIO-a3f7c07d

    希望对你有所帮助。

    Best Regards,
    Sera Yu


    MSDN Community Support<br/> Please remember to click &quot;Mark as Answer&quot; the responses that resolved your issue, and to click &quot;Unmark as Answer&quot; if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact <a href="mailto:MSDNFSF@microsoft.com">MSDNFSF@microsoft.com</a>.

    2017年7月6日 9:49