• 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重置信号状态的。

  • 相关阅读:
    MC9S12 硬件设计
    ESD
    选用与使用稳压二极管的介绍
    MOSFET 栅极电阻作用及其选型
    orcad常用库文件介绍
    开关电源和LDO的区别
    续流二极管的作用及选型
    为什么大电容滤低频小电容滤高频的问题
    Java常用API——时间类
    Idea问题:“marketplace plugins are not loaded”解决方案
  • 原文地址:https://www.cnblogs.com/jyj666/p/15885765.html
Copyright © 2020-2023  润新知