2013-12-18 16 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()};'。哦,是的,正如其他人所說,擺脫睡眠呼叫。 –