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

 

posted @ 2022-02-12 11:26  苏州の酱醋茶  阅读(5213)  评论(1编辑  收藏  举报