C#多線程控制串口收發信息(基於AutoResetEvent實現)


首先,先說明為什么要使用多線程來控制串口收發信息。我們知道在Winform和WPF內,界面線程是主線程,如果你在主線程控制串口收發信息的話,會導致頁面假死,給客戶不良好的使用體驗,因此多線程控制串口通信是為優化客戶使用體驗而生的。

在微軟官方提供的類庫里,有很多方法可以實現這一操作,在這篇博文中,我主要介紹使用AutoResetEvent來實現這一操作。

當然我后續的博文里我也會提供使用Task相關類庫來實現這一操作。

那么AutoResetEvent的主要應用場景就是兩個線程間的"阻塞通信",可以通過AutoResetEvent簡單的在一個線程里面控制另一個線程的阻塞,使用起來及其方便,但是需要注意AutoResetEvent的狀態的變化控制!

廢話不多說,上代碼!(AutoResetEvent來自Threading命名空間,如果使用高版本比如.NET 6注意自行手動添加引用)

首先定義AutoResetEvent,構造函數里的false是他默認的狀態。

private AutoResetEvent resetEvent = new AutoResetEvent(false);

然后我們默認你已經開發完畢了發送命令,我們新建一個函數,用於執行串口發送命令:

private void SendMessage()
{
  byte[] data = null;
  StringBuilder sb_0x10 = new StringBuilder();

  if (SerialPortCtrler.Instance.SendCommand((byte)Convert.ToInt32(Convert.ToInt32(model_0x10.ID.ToString(), 16)), data))
  {
    sb_0x10.Append("發送模塊復位成功,");
    sb_0x10.Append(resetEvent.WaitOne(Const.waitOneTime) ? "並收到下位機回復。" : "但未收到下位機回復");

    //這是用於顯示界面信息的消息隊列,不是本文所介紹的重點可忽略。
    //queueState.Enqueue(sb_0x10.ToString());
  }
  else
  {
    //queueState.Enqueue("發送模塊復位失敗");
  }
}

 

 

這里我們注意WaitOne方法是一個類似於阻塞等待的方法,當線程執行到此步后,會等待WaitOne方法中傳入的毫秒數,在收到Set信號后,此AutoResetEvent的狀態會被置為true,否則會一直等待到時間結束,當到達限定時間仍沒收到Set的信號時,此WaitOne會返回false。所以需要注意的是此函數需要由另一個線程來執行:

thread = new Thread(SendPhotonCal);
thread.Start();

那么發送我們代碼編寫完畢了,如何處理串口接收呢?其實很簡單,這里我是使用的win32的消息通知機制來處理消息的接收(這里如果不了解消息通知的小伙伴可以使用輪詢來做個實驗,這里不再贅述),然而這並不是重點,重點是如何處理這個AutoResetEvent的waitone等待。不過其實應用代碼也很簡單,僅一句話:

resetEvent.Set();
     public override void OnMessage(MessageParameters msg)
        {
            bool result = false;switch (msg.Msg)
            {
                case (int)Command.Reset:
                    result = BitConverter.ToInt32(((byte[])msg.Param), 2) == 0;
                    if (result)
                    {
                        strTemp = "模塊復位成功!";
                        resetEvent.Set();
                    }
                    else
                    {
                        errorCode = BitConverter.ToInt32(((byte[])msg.Param).Reverse().ToArray(), 2).ToString("X");
                        strTemp = "模塊復位失敗" + errorCode;
                        resetEvent.Set();
                    }

                    break;
        }
      }

這時一個簡單的多線程串口收發程序就編寫完畢了。

需要注意的是AutoResetEvent常用的是三個函數,這里提及了兩個,另一個是Reset(),一般情況下,如果是單線程使用了AutoResetEvent在waitone之前是需要Reset重置信號狀態的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM