2016-06-28 222 views
1

我維持MFC程序,可以從計算機A通過RS232發送數據到計算機B。有時它會順利傳輸數據,但有時它會永遠掛起。有兩個線程按順序將相同的數據發送到COM端口。第一個線程成功發送數據,但第二個線程掛在代碼「WriteFile」上。當計算機A上的第二個線程掛起,在「WriteFile的」,我發送一些無意義的數據,如「1」,從B計算機回到計算機A,然後在電腦上懸掛的「WriteFile的」 A站掛了,B電腦終於看到數據由計算機A上的第二個線程發送。「WriteFile的」使用MFC RS232通訊掛起永遠,但

這裏是RS232 log from computer B

圖爲在計算機A上兩個線程開始有自己的測試和將消息發送回計算機B.每個線程完成有自己的測試,幾乎在同一時間發送TEST_DONE到計算機B。但是,計算機B只能看到計算機A上的第一個線程發送的TEST_DONE(第二個線程掛在WriteFile此處),直到我從計算機B手動向計算機A發送「1」。

這是我的代碼發送從計算機一則消息,計算機B. CMD的長度爲255

BOOL SerialPort::AutoHandlerRES(unsigned char* cmd){ 
while(wait_transfer.IsLocked()) 
    Sleep(1000); 
wait_transfer.Lock(); 
CString out; 
BOOL RetB; 
UCHAR EndChar[2]={0x0D,0x0A}; 
out=CString(cmd); 
DWORD num = out.GetLength()+2; 
cmd[num-2]=EndChar[0]; 
cmd[num-1]=EndChar[1]; 
RetB=WriteFile(this->m_hCom, cmd, num, &num, NULL); 
Sleep(1000); 
wait_transfer.Unlock(); 
return RetB;} 

我的問題是,可能是什麼原因可能造成線程B掛在「WriteFile的」?爲什麼掛線不會發生在線程A上?謝謝!

+0

這可能是無關的問題,但你正在使用的鎖錯了。如果鎖未打開,'.Lock()'的要點是等待。你不必等待自己。第二次睡眠也是可疑的。 – ElderBug

+0

對不起,我沒有很好地解釋功能。該函數將被許多線程調用,並且所有線程使用相同的RS232 COM端口句柄。所以我使用lock來確保線程一次使用WriteFile。 – ohnotme

+0

這並沒有改變我的觀點:你錯用了它。不應該有任何while()和Sleep()。 – ElderBug

回答

1

the MSDN page about serial communications

如果一個線程被阻塞,等待它的I/O操作完成, 所有其他線程繼續調用通信API將 阻塞,直到原來的操作完成。舉例來說,如果一個線程 在等待一個ReadFile函數返回,任何其他 線程發出一個WriteFile函數將被阻止。

您可能會發出阻止ReadFile阻止WriteFile完成。在你的情況下,這將是線程之間的競爭條件;寫操作通常在調用讀取之前完成,但並不總是如此。

防止這種情況的最好方法是不要不小心地調用ReadFile,而是將它與寫入一樣封裝在同一個鎖中,並在讀取之前等待接收COMM事件。原始的Win32調用是SetCommMaskWaitCommEvent。然後您可以使用ClearCommError來檢測應該讀取多少個字節(因爲接收事件不會告訴您接收了多少數據)。

您還可以使用重疊IO允許同時IO。我覺得它更清潔,但並不簡單。

+0

我應該修改我的代碼,通過檢查COMM事件來檢查傳入的RS232數據,而不是無休止地讀取RS232。非常感謝你! – ohnotme