我設定了一個定時器用來做串口通訊超時重發機制的。
我在除錯程式的時候遇到:觸發重發機制內設定的自動跳轉到下一個串口的代碼,切換串口之后(關閉當前串口然后打開下一個串口)。執行緒中開始報錯,提示埠被關閉。
按照我個人的理解,不是應該超時事件執行完之后再回到執行緒中繼續執行代碼嗎。那么就應該是在我關閉串口并打開下一個串口,更改state步驟之后再回到執行緒中執行while回圈才對啊。
// 定時器初始化
private void TimerInit()
{
timer = new System.Timers.Timer();
timer.Interval = 500;
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = true ;
timer.Enabled = true;
}
// 關閉串口
private void CloseComPort(SerialPort sP)
{
if (sP.IsOpen == true)
{
Application.DoEvents();
sP.Close();//在此處執行完之后,執行緒中就報錯埠被關閉。
}
}
private bool ConfigComPort(string pName)
{
try
{
sP.PortName = pName;
sP.BaudRate = 9600;
sP.DataBits = 8;
sP.Parity = System.IO.Ports.Parity.None;
sP.StopBits = System.IO.Ports.StopBits.One;
sP.WriteBufferSize = 1024;
sP.ReadBufferSize = 1024;
sP.DtrEnable = true;
sP.RtsEnable = true;
sP.Open();
return true;
}
catch
{
return false;
}
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
string[] str = SerialPort.GetPortNames();
if (flagRetry == false)
{
flagRetry = true;
if ((--timesForRetry) == 0)//重發五次
{
if ((state == STATE.STATE_Read_HandShake) && (flg == 1))
{
CloseComPort(sP);//重發五次之后關閉串口搜尋下一個串口
if (pIdx < str.Length)
{
if (ConfigComPort(str[pIdx++]))//串口初始化,打開串口
{
timesForRetry = 5;
flagRetry = false;
state = STATE.STATE_Send_HandShake;
//return;
}
}
else
{ flagTransmitting = false; }
}
else
{
flagTransmitting = false;
}
}
else
{
if ((state == STATE.STATE_Read_HandShake) && (flg == 1))
{
state = STATE.STATE_Send_HandShake;
}
flagRetry = false;
}
}
uj5u.com熱心網友回復:
設斷點、單步除錯就感覺這個定時器事件跟執行緒是穿插交接執行的一樣,上一步還在自己的事件里執行,下一步就到執行緒中去執行代碼了,然后下一步又回到定時器事件中,各位大神麻煩指點一下,這個對我的程式很重要!!!uj5u.com熱心網友回復:
在定時器和執行緒里面加個鎖是最直接的解決方法,你也可以修改下自己的邏輯加一個狀態標識,在接收資料時判斷下狀態,不進入串口切換uj5u.com熱心網友回復:
這下你該知道System.Timers.Timer本身是多執行緒定時器了吧?沒看你代碼,估計是你定時器方法里作了關閉埠操作,然后其它執行緒里卻還要使用該埠。
uj5u.com熱心網友回復:
現在知道是多執行緒了,我是在定時器里做了關閉埠然后打開另一個串口,就是ConfigComPort(str[pIdx++])這個方法里就是打開埠。之后再回到主執行緒里去執行程式去了。我是這樣子想的覺得沒什么問題,以為回到主執行緒中去的時候埠應該是已經打開的狀態的。
不知道是不是因為我是斷點除錯狀態。所以這個例外觸發率特別高
但是我讓程式無斷點運行也是容易在切換串口的時候爆出例外。
后來在主執行緒代碼里加了Thread.Sleep(150); 和if(!sP.Isopen) {break;},防止再出現例外。還是會偶有發生這種問題,但是也算是比之前穩定了。
uj5u.com熱心網友回復:
同時 Application.DoEvents(); 也是異步執行的。uj5u.com熱心網友回復:
定時器最好在執行前將定時器執行設定為false 執行完成之后設定為true。類似加鎖的操作uj5u.com熱心網友回復:
特別是在定時間隔小于執行時間的情況下。uj5u.com熱心網友回復:
得,不要用單步除錯。你得習慣,這不是一個簡單控制臺。你要搞單步除錯?如果你override一下WndProc,別說你有個timer,你就是一個空白的沒有任何控制元件的表單,你試試看單步的效果。
你的例外跟什么到處飛,沒有半點關系。
那是因為你關了串口,沒關定時器
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/41600.html
標籤:C#
