使用隊列實現串口實時讀寫


好久沒寫博客了。上一次還是2015年。。。。

寫C#同時讀寫串口,也就是發送讀取、寫入到串口,之前的做法,定時循環讀取,又需要的地方寫入,而且加lock

 1 public void Read(){
 2     while(true){
 3        lock(this)
 4          SerialPort.Write(讀取的命令內容1);  
 5        Thread.sleep(500); 
 6        lock(this) 
 7             SerialPort.Write(讀取的命令內容2);  
 8        Thread.sleep(500); 
 9        //..可能還有....
10     }
11      
12 }
13 
14 public void Write1(){
15   lock(this)
16        SerialPort.Write(寫入的命令內容);      
17 }
18 
19 public void Write2(){
20   lock(this)
21        SerialPort.Write(寫入的命令內容);      
22 }

 

后來,參考網上的前輩思路,用隊列,生產者/消費者模式,把需要寫入串口的命令放到隊列里(Quere<T>),用一個線程專門負責用隊列里取出數據並寫入串口,這個思路不錯。試了一下

這里主要是用modbus slave工具,模擬串口工具VSPD做一組模擬串口,slave工具初始化,C#去讀寫數據。

一開始隊列使用

  1 private static Queue<byte[]> cmdList = new Queue<byte[]>(); 

讀取/寫入的入隊

 1 /// <summary>
 2         /// 讀取寄存器狀態,200ms讀一次
 3         /// </summary>
 4         /// <returns></returns>
 5         static async Task Read()
 6         {
 7             while (true)
 8             {
 9                 //從0,讀10個寄存器
10                 byte[] send = new byte[]
11                 {
12                  0x01,0x03,0,0,0,0x0A
13                 };
14                 Enqueue(send);
15                 await Task.Delay(200);
16             }
17         }
18 
19  /// <summary>
20         /// 寫寄存器操作
21         /// </summary>
22         /// <returns></returns>
23         static async Task Write()
24         {
25             for (short i = 0; i < 10; i++)
26             {
27                 var index = BitConverter.GetBytes(i);
28 
29                 for (short j = 0; j < 10; j++)
30                 {
31                     var data = BitConverter.GetBytes(j);
32                     byte[] send = new byte[] {
33                         0x01,0x06,index[1],index[0],data[1],data[0]
34                         };
35                     Enqueue(send);
36                     await Task.Delay(1000);
37                 };
38             }
39         }
40 
41  /// <summary>
42         /// 添加進隊列
43         /// </summary>
44         /// <param name="send"></param>
45         private static void Enqueue(byte[] send)
46         {
47              cmdList.Enqueue(send);
49         }

取出,並發送

    /// <summary>
        /// 從隊列里取出內容並發送
        /// </summary>
        /// <returns></returns>
        static async Task Loop()
        {
            while (true)
            {
                if (cmdList.Count > 0)
                { 
                  var send = cmdList.Dequeue;
                    
                    //發送操作
                    var sendByte = crc16(send);
                    sp.Write(sendByte, 0, sendByte.Length);
            await Task.Delay(50);//加上這句似乎就可以正常運行了。。。。之前沒加才有了接下來的內容。 }
else { await Task.Delay(50); } } }

然后Task.Run(async()=>{Loop();});似乎就可以了,由於每次發送完我沒加Delay(),導致我在slave工具中看到黏包的現象

一次收到2條C#發來的命令,一度懷疑發送的時候,命令就是連一起發的,隊列里面的內容被2個線程同時添加了命令,帶着這個疑問,問了老朋友,結果他發來一個地址,講的《C#中線程安全集合篇》。

線程安全的集合類,

.net framework4新引入的五個專門支持多線程添加和刪除操作而設計的集合類型。不同於以前版本的中集合類型中的SyncRoot屬性 以及 Synchronized()方法,這些新類型使用了高效的鎖定和免鎖定同步機制

ConcurrentQueue(T)
ConcurrentStack(T)
ConcurrentDictionary(TKey, TValue)
ConcurrentBag(T)
BlockingCollection(T)

后來改了代碼,使用的是BlockingCollection(T)

 1 static BlockingCollection<byte[]> cmdListBlocking = new BlockingCollection<byte[]>();
 2 
 3         /// <summary>
 4         /// 添加進隊列
 5         /// </summary>
 6         /// <param name="send"></param>
 7         private static void Enqueue(byte[] send)
 8         {
 9             cmdListBlocking.Add(send);
10         }
11 
12       //取出來,並發送
13      Task.Factory.StartNew(async () =>
14             {
15                 foreach (var vale in cmdListBlocking.GetConsumingEnumerable())
16                 {
17                     //發送操作
18                     var sendByte = crc16(vale);
19                     sp.Write(sendByte, 0, sendByte.Length);
20                     await Task.Delay(50);//依然要加Delay()...
21                 }
22             });

不加Task.Delay(50)還是會出現黏包的命令,可能是串口發送數據緩沖區?如果同時進行2個 Task.Run(async()=> { await Write(); });,不加Delay(),是寫不上數據的,哪位大神告訴是什么原因呢,對串口發送數據機制還是不夠理解。。。

做個備份

參考:https://www.cnblogs.com/chengxiaohui/articles/5672768.html  C# 4.0 之線程安全集合篇

 

 


免責聲明!

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



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