自從用上了C#,那真的叫一個爽,再也不用寫函式宣告,再也不用去手動釋放記憶體,一個ToString函數,基本所有的類型轉換都完成… …
但是爽是有代價的,比如用著用著毫無徵兆的退出了,比如,程式裡面一堆堆的try catch仍舊抓不到那個錯誤在哪裡… …
如果以上的問題都可以容忍,依舊會有問題你沒有辦法容忍,比如今天要說的SerialPotr類阻塞問題。
該程式是COBAS8000電化學發光分析儀的介面,一開始就是用c#寫的,使用了c#內建的SerailPort類。
先說說程式邏輯:
1、介面程式收到COBAS8000發送的條碼請求。
2、介面程式到LIS資料庫中找到要做的相應的項目。
3、介面程式發送ENQ.
4、儀器回複ACK後,介面程式將要做的項目發送給儀器。
發送部分的核心代碼如下:
代碼如下 |
複製代碼 |
public void SendOrder(OrderRecord order) { string strSend = ""; HeaderRecord head = new HeaderRecord(); strSend+=head.GetString(); PatientRecord patient = new PatientRecord(); strSend+=patient.GetString(); strSend += Encoding.ASCII.GetString(order.GetBytes()); TerminationRecord termination=new TerminationRecord(); strSend += termination.GetString(); byte[] btSend=this.GetFrameBytes(Encoding.ASCII.GetBytes(strSend)); Log log = new Log(); log.Write("已準備好發送資料!"); this.sendBytes = btSend; this.State = ComState.Sending; this.IsSended = false; log.Write("馬上發送ENQ!"); this.SendENQ(); dtENQSend = DateTime.Now; this.IsSendingENQ = true; } |
現在我們遇到的問題是:當介面程式收到條碼請求,並在LIS中找到了項目,然後準備發送ENQ給裝置的時候,卡死了!!!!!!
從日誌上看,程式就停留在(”馬上發送ENQ!”)不動了!
調用的函數是:
代碼如下 |
複製代碼 |
serialPort.Write(bytes, 0, bytes.Length); |
到這裡程式就死了。
由於COBAS8000的逾時時間是18秒,等到18秒後,儀器就將該條碼的標本當做沒有項目處理了,之後,它將繼續發送下一個條碼的請求!然後程式就又活了!!!!
於是乎,我寫的那個介面每天就出現這樣一種情況:
當大批量的標本上機之後,中間總會有一兩個沒有項目,將這兩個標本挑出來,再上一遍,它又好了!!!
吵吵嘗試和排除了以下幾種情況:
1、由於UI和介面造成的程式假死,使得serialport沒有將資訊發送成功,於是我取消了所有的UI,經大規模標本測試,依舊會有一兩個掃不上!
2、由於線程造成的鎖死,於是乎我重新將讀取放到一個獨立的線程,使得串口的讀寫進行了分離,結果呢,還是會出問題。
最大的問題是平常標本不多的時候,一點問題都沒有,大規模標本上上去後,就一兩個出問題,serialPort的write方法,肯定在某個地方是有問題的,興許是線程阻塞吧,但是由於看不到原始碼,著實沒有辦法去跟蹤解決。而且偶爾出現問題,這個問題本身就很難解決。
最後,祭出我的殺手鐧,用串口的API來寫吧,考慮到我原來在C++中用的多線程串口類很成熟,於是乎花了四天時間,用c++重新寫了介面。調試了兩個多月的問題,其實還不如四天重寫解決問題快!
最後總結一下,如果要求高的程式,c/c++依舊是主流,c#嗎?開發之前,一定要考慮好,一定要做好出問題的打算