Windows WriteFile和ReadFile相互干扰

时间:2014-09-18 07:21:28

标签: windows multithreading file-io

我有两个线程,一个调用WriteFile,另一个调用ReadFile,两个都在115200使用相同的串口。我反复发现的是,当我在写线程中添加更多顺序WriteFile调用时,是我有一个检查和失败次数增加,即数据损坏。如果我在写入线程中使用WriteFile调用之间添加延迟(使用CBaseDLIMessage :: CrossSleep(20)),则校验和错误会减少甚至完全消失(取决于休眠时间),但是在添加其他内容时会出现问题WriteFile方法。

WriteFile方法是否有可能以某种方式将数据写入共享缓冲区,共享缓冲区也用于读取(在驱动程序级别),随后会破坏我的读取数据?

我的串口设置代码如下所示:

CommHandle OpenSerialPort(int nId, long baud)
{

#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
    char szCOM[16];

    /* COM waiting */
    COMMTIMEOUTS g_cto =
    {
        MAXDWORD,       /* ReadIntervalTimeOut          */
        0,              /* ReadTotalTimeOutMultiplier    */
        0,              /* ReadTotalTimeOutConstant  */
        0,              /* WriteTotalTimeOutMultiplier  */
        0               /* WriteTotalTimeOutConstant   */
    };

    /* COM configuration */
    DCB g_dcb =
    {
        sizeof(DCB),            /* DCBlength            */
        baud,                   /* BaudRate             */
        TRUE,                   /* fBinary              */
        FALSE,                  /* fParity              */
        FALSE,                  /* fOutxCtsFlow         */
        FALSE,                  /* fOutxDsrFlow         */
        DTR_CONTROL_DISABLE,    /* fDtrControl          */
        FALSE,                  /* fDsrSensitivity      */
        FALSE,                  /* fTXContinueOnXoff    */
        FALSE,                  /* fOutX                */
        FALSE,                  /* fInX                 */
        FALSE,                  /* fErrorChar           */
        FALSE,                  /* fNull                */
        RTS_CONTROL_DISABLE,    /* fRtsControl          */
        FALSE,                  /* fAbortOnError        */
        0,                      /* fDummy2              */
        0,                      /* wReserved            */
        0x100,                  /* XonLim               */
        0x100,                  /* XoffLim              */
        8,                      /* ByteSize             */
        NOPARITY,               /* Parity               */
        ONESTOPBIT,             /* StopBits             */
        0x11,                   /* XonChar              */
        0x13,                   /* XoffChar             */
        '?',                    /* ErrorChar            */
        0x1A,                   /* EofChar              */
        0x10                    /* EvtChar              */
    };

    //cout << "COM:::" << nId;
    sprintf(szCOM, "\\\\.\\COM%d", nId);
    HANDLE hCOM = CreateFile(szCOM,             /* lpFileName               */
        GENERIC_READ|GENERIC_WRITE,             /* dwDesiredAccess          */
        0,                                      /* dwShareMode              */
        NULL,                                   /* lpSecurityAttributes     */
        OPEN_EXISTING,                          /* dwCreationDisposition    */
        FILE_ATTRIBUTE_SYSTEM,                  /* dwFlagsAndAttributes     */
        NULL);                                  /* hTemplateFile            */
    //std::cout << "COM: " << (int)nId << "\n";
    if(hCOM == INVALID_HANDLE_VALUE)
    {
        //std::cout << "INVALID_HANDLE_VALUE \n" ;
        DWORD err = GetLastError();
        if (err == ERROR_FILE_NOT_FOUND)
        { 
            std::cout << "Error: Failed to open COM[" << nId << "]\n";  
        }    
        else if(err == ERROR_INVALID_NAME)
        {      
            std::cout << "\nError: \n%s 'filename, directory name, or volume label syntax is incorrect'\n";  //error code 0x7B
        }    
        else
        {
            //cout << "\nHandle creation error code: %x\n" << err; 
        }

        return 0;
    }
    else
    {
        std::cout << "COM[" << nId << "] OPEN. Baud: " << baud <<"\n";
    }

    // COM buffer size
    SetupComm(hCOM, RX_SIZE, TX_SIZE);

    // COM config
    if(!SetCommTimeouts(hCOM, &g_cto) || !SetCommState(hCOM, &g_dcb))
    {
        CloseHandle(hCOM);
        return 0;
    }

    // COM buffer purge
    PurgeComm(hCOM, PURGE_TXCLEAR|PURGE_RXCLEAR|PURGE_TXABORT|PURGE_RXABORT);
    EscapeCommFunction(hCOM, SETDTR);
    return hCOM;

#else
    wxSerialPort *pwxSerialPort = new wxSerialPort();
    char szPort[32];
    sprintf(szPort,"com%d", nId);
    if(pwxSerialPort->Open(szPort) < 0) {
        return 0;
    }
    // set the baudrate
    pwxSerialPort->SetBaudRate((wxBaud)baud);
    return pwxSerialPort;
#endif
}

int CloseSerialPort(CommHandle hSerialPort)
{
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
    CloseHandle(hSerialPort);
    return 1;
#else
    hSerialPort->Close();
    delete hSerialPort;
    return 1;
#endif
}

int WriteDataToSerialPort(CommHandle hSerialPort, void *pMsg, unsigned short messageLength, unsigned int *pBytesWritten)
{

    *pBytesWritten = 0;
    if(hSerialPort == 0)
    {
        //cout << "hSerialPort ====== 0";
        return -1;
    }
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
    return WriteFile(hSerialPort, (char*)pMsg, messageLength, (DWORD*)pBytesWritten, NULL);
#else
    *pBytesWritten = hSerialPort->Write((char*)pMsg, messageLength);
    return 1;
#endif
}

int ReadDataFromSerialPort(CommHandle hSerialPort, void *pMsg, unsigned short messageLength, unsigned int *pBytesRead)
{
    unsigned short i;
    *pBytesRead = 0;
    i = 0;
    if(hSerialPort == 0)
    {
        return -1;
    }
#if defined(USE_WINDOWS_SERIAL_PORT_LIB)
    return ReadFile(hSerialPort, (char*)pMsg, messageLength, (DWORD*)pBytesRead, NULL);
#else
    *pBytesRead = hSerialPort->Read((char*)pMsg, messageLength);
    return 1;
#endif
}

1 个答案:

答案 0 :(得分:0)

通过串口通讯速度很慢。

您应该使用WriteFileEx而不是WriteFile。

您可以指定在写入(传输)完成或失败时可以执行的例程。 如果在执行该例程后写入下一个数据,则可能不会发生数据溢出。