既然是秘籍,顯然是寫一些大家不常找到的,MSDN里遺漏提示大家注意的東西。
用過.net 2.0中,自帶SerialPort的人,大多都遇到過。莫名其妙的執行Close的時候會死掉的問題。而Wince,mobile下,甚至Write,WriteLine的時候也會死鎖。這和串口底層驅動有關。
1.Close的時候死機問題
我只是猜測,Close執行的操作是調用2個API:
SetCommMask(m_hComPort,0);WaitForSingleObject(m_pThread->m_hThread,INFINITE);m_pThread=NULL;if(m_hComPort!=INVALID_HANDLE_VALUE) CloseHandle(m_hComPort);
這里的話,SetCommMask操作的時候。如果你的DeviceReceived事件沒執行完,里面還有更新界面的操作。就會監聽線程在等待,執行到界面操作,界面又要求關閉監聽線程然后關閉串口。死鎖了。
[解決辦法]
一個正確不會死機的串口程序(主要是DataReceived事件里如果要調用ui來顯示數據或分析結果的時候。ui的效率不確定,ui可能快。可能慢,可能用戶某個操作阻塞中,會導致DataReceived事件執行很長時間,不論如何,這個時間我們無法預料)。
應該在關閉之前執行這句
while (Environment.TickCount - i < 2000 && _isReceiving) application.DoEvents();
2.WriteLine,Write死鎖
串口必然會讀寫超時,你無法預測你軟件運行的硬件都足夠快,串口驅動都效率很高。并且讀寫超時是正常現象。但是微軟的SerialPort類默認的讀寫超時都是-1,無限等待,如果串口驅動有效率陷阱,超時了。Write和WriteLine就導致軟件死鎖無法繼續使用了。
[解決辦法]
設置讀寫超時為1000毫秒
3.不知道有人注意過沒,WriteLine好像和Write效果一樣?不是一個錯誤,而是微軟一個很奇怪的設計,他允許設置換行符,默認是"",你需要自己設置NewLine屬性為"/r/n"。否則Write和WriteLine是一樣的。
--------------------------------------------------------------------------------
下面演示一個標準的,不會軟件死鎖的基于SerialPort的例子:
using System;using System.Drawing;using System.Text;using System.Windows.Forms;using System.IO.Ports;using System.Collections.Generic;
namespace SerialSample{ public partial class FormSerialSample : Form { //Fields SerialPort _comm = new SerialPort("COM1", 19200); bool _isReceiving = false; //wince下4096字節為一頁,一次分配一頁內存可能會快。但不知道托管內存是否也如此 List<byte> buf = new List<byte>(4096);
//Construct public FormSerialSample() { InitializeComponent(); }
bool Open() { _comm.WriteTimeout = 1000;//寫超時,如果底層串口驅動效率問題,能有效的避免死鎖 _comm.ReadTimeout = 1000;//讀超時,同上 _comm.NewLine = "/r/n";//新行的文本,用于WriteLine方法中由系統附加在text后 _comm.DataReceived += OnComm;//注冊事件 _comm.Open();//打開串口 return _comm.IsOpen;//返回打開結果 }
void Close() { //這里需要允許OnComm方法執行完。如果不這么做。可能會 //先由某個地方執行到了Close,然后監聽線程觸發,調用了OnComm //OnComm執行完緩存,執行this.Invoke。不知道Invoke原理。可能是 //消息機制?那么你如果正在這個函數里,不釋放的時候,你就不會繼續 //處理消息,所以我們要關閉之前,手工的調用消息處理函數 _comm.DataReceived -= OnComm;//反注冊事件,避免下次再執行進來。 //最大延遲2秒,并檢測到OnComm退出則退出,處理系統消息隊列中的消息 int i = Environment.TickCount; while (Environment.TickCount - i < 2000 && _isReceiving) Application.DoEvents(); _comm.Close();//現在沒有死鎖了,關閉串口 }
void OnComm(object sender, SerialDataReceivedEventArgs e) { _isReceiving = true;//開始讀
//緩存你的數據,注意,最好在Invoke之外緩存數據,只有更新UI的才需要Invoke int count = _comm.BytesToRead; if (count < 1) return; byte[] tmpBuf = new byte[count]; _comm.Read(tmpBuf, 0, count); //連續3k數據沒分析,應該沒啥用了。 //避免數據太多分析時候時間長導致效率明顯下降 if (buf.Count > 3000) buf.Clear(); buf.AddRange(tmpBuf);
//分析數據 //自己實現
//匿名委托,用于this.Invoke調用。 EventHandler delUpdate = delegate { //執行你的更新ui操作 }; this.Invoke(delUpdate);
_isReceiving = false;//結束讀 } }}
串口是沒啥技術含量。但是這個微軟的SerialPort實在給不少人帶來了麻煩,死機是絕大多數人遇到的,我以前是MSDN,微軟的技術論壇,CSDN,GOOGLE,Baidu都搜索了。甚至發了郵件給微軟的wince開發組,沒有任何答案。不求您覺得我寫的有什么價值,但希望對有同樣困惑的朋友。能搜索到此文章時候,解決一個隱含的問題。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/wuyazhe/archive/2009/01/17/3806248.aspx
新聞熱點
疑難解答