2013-12-18 17 views
0

我在写一个C++应用程序,用于半双工通信从设备下载数据。以下是我用于串行通信的课程。串行通信读取不能正常工作

class CSerialCommHelper 
{ 
    HANDLE m_pPortHandle;   //Handle to the COM port 
    HANDLE m_hReadThread;   //Handle to the Read thread 
    HANDLE m_hPortMutex;   //Handle to Port Mutex 
    std::wstring m_strPortName;  //Portname 
    COMMTIMEOUTS m_CommTimeouts; //Communication Timeout Structure 
    _DCB dcb;      //Device Control Block 
    DWORD m_dwThreadID;    //Thread ID 
    string m_strBuffer; 

public: 
    CSerialCommHelper(); 
    HRESULT Open(); 
    HRESULT ConfigPort(); 
    static void * ReadThread(void *); 
    HRESULT Write(const unsigned char *,DWORD); 
    string GetFrameFromBuffer(); 
    HRESULT Close(); 
    ~CSerialCommHelper(void); 
}; 

ReadThread和写入功能如下:对于readthread释放互斥

void * CSerialCommHelper::ReadThread(void * pObj) 
    { 
    CSerialCommHelper *pCSerialCommHelper =(CSerialCommHelper *)pObj; 
    DWORD dwBytesTransferred =0; 
    DWORD byte=0;; 

    while (pCSerialCommHelper->m_pPortHandle != INVALID_HANDLE_VALUE) 
    { 
     pCSerialCommHelper->m_strBuffer.clear(); 
     pCSerialCommHelper->m_usBufSize=0; 

     WaitForSingleObject(pCSerialCommHelper->m_hPortMutex,INFINITE); 

     do 
     { 
      dwBytesTransferred = 0; 


      ReadFile (pCSerialCommHelper->m_pPortHandle,&byte,1,&dwBytesTransferred,NULL); 
      if (dwBytesTransferred == 1) 
      { 
       pCSerialCommHelper->m_strBuffer.push_back((char)byte); 
       pCSerialCommHelper->m_usBufSize++; 
       continue; 
      } 


     } 
     while ((dwBytesTransferred == 1) && (pCSerialCommHelper->m_pPortHandle != INVALID_HANDLE_VALUE)); 


      ReleaseMutex(pCSerialCommHelper->m_hPortMutex); 
      Sleep(2); 


    } 
    ExitThread(0); 


    return 0; 

}

写入功能等待和写入数据到端口。 GetFrameFromBuffer将从使用SerialCommhelper 的应用程序中调用,并返回m_strBuffer字符串。

我的问题是每当我试图下载大量的数据。 我正在丢失一些数据帧。 我得到的设备响应时间在.0468到.1716秒之间。

经过分析不同的错误情况后,我才知道,随着其他帧以相同的时间间隔下载,它不会出现问题。

调用getframebuffer的函数不断调用它,直到得到填充的字符串。

+0

一个传球笔记,也许无关。当你像这样抛出这个参数时,你认为无论函数是否开始,线程(及其数据)的寿命都会比线程长。不要假定这样的事情是安全的,而应保留一个本地副本。但是,也许你已经想过了,并且有一些你正在传递的全局实例 –

+0

我曾经在一个项目上工作过,一旦使用了非常相似的方法从投影仪读取串行数据,这些数据也会间歇性地失败。不幸的是,我们从来不知道为什么,但改变阅读方法来使用[Completion Routines](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365601%28v=vs.85%29。 aspx)解决了这个问题。 – parrowdice

+1

Sleep()调用非常可疑,将其删除并解决实际问题。 m_hPortMutex也非常令人毛骨悚然,当多线程调用ReadFile并且每个线程都获得一条数据时,没有什么好事发生。你没有希望再次精确地将它们粘在一起。 –

回答

2

好像这两个语句不应该在你的外循环while

pCSerialCommHelper->m_strBuffer.clear(); 
    pCSerialCommHelper->m_usBufSize=0; 

你内心的,而循环读取字节,只要他们立即可用,而外环做了Sleep(2)瞬间内部循环不会给你一个字节。

如果您在等待整个数据包可用,那么您应该保持循环,直到获得所有字节,而不清除整个过程。

我真的不知道ReadFile API,但我猜ReadFile可能会返回0,如果没有可立即使用的字节,或至少可以通过打开串行设备时指定的任何超时值来获得。

2
 ReleaseMutex(pCSerialCommHelper->m_hPortMutex); 
     Sleep(2); 

That Sleep()调用隐藏了真正的问题。它是永不正确的线程代码,总是一个时间错误的创可贴。

你当然似乎有一个,即m_hPortMutex法术厄运以及。如果你确实有多个线程试图从串口读取数据,那么他们将开始争夺该互斥锁。结果会很差,每个线程都会从端口获得一些字节。但显然你想读取一个数据帧。没有希望,你可以将每个线程重新组合在一起的几个字节组合成一个帧,你已经失去了它们的序列。所以睡了一会儿似乎像一个解决方法,它注入延迟,可以给你一个更好的阅读框架拍摄。通常,并不总是。你也写错了地方。

此代码刚刚坏掉。删除睡眠()。做不是退出循环,直到你读完了整个帧。

+0

只有一个ReadThread用于从一个端口读取整个帧。睡眠(2)函数确保Write()将能够获取端口互斥量,以便它可以将命令写入端口。 我首先尝试不使用Sleep(2),它以死锁结束,Readthread立即获取释放的互斥锁。所以写功能将失败。 – kernel

+2

使用Sleep()解决死锁问题更糟糕,那么迟早会失败。串口支持同时读写,不需要互斥。一个核心问题是你的代码实际上并没有做任何事情来确保接收到整个帧。当没有更多字节需要阅读时,你退出了,那是错误的。串行端口非常慢。 –

+0

+1,'只使用一个ReadThread' - 那么你根本不需要互斥锁。 tx和rx路径是独立的,可以由两个线程处理而不锁定。我看不到写电话?此外,它看起来像你不断创建,终止和销毁半双工通信的线程。你应该只需要一个带有循环的线程:'while(true){read(); write()};'。哦,是的,正如其他人所说,摆脱睡眠呼叫。 –