使用队列实现串口实时读写

好久没写博客了。上一次还是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 之线程安全集合篇

 

 

posted @ 2018-02-01 17:31  WaitingEver  阅读(6803)  评论(1编辑  收藏  举报