项目背景:
公司要做一个温控软件,需要协调三个串口同时收发,控制三个温控模块,重点是程序需要在查询温度的同时,还要下发控制指令给模块(升降温指令),这两个操作都得一写一读,因为它们返回的数据格式可以说是毫不相关,写在串口接收事件里的话没办法对接收的数据做一个有效的处理。
下发升降温指令的时间是不确定的,只能单独开一个线程来做,查询又执行的很快,50ms一次,很有可能出现两个线程几乎同时给串口写指令,又同时在读。这时候如果升降温线程读出来的是温度查询的返回值,温度查询那块读出来的又是升降温指令的返回值的话,程序就乱套了。
所以必须要加锁,才能确保程序在每次串口写操作后必须完成读操作后,才能进行下次对串口的操作,否则下次操作就一直等待,直到上次操作完成。
示例代码:
private object obj = new object();
/// <summary>
/// 按指令设置参数
/// </summary>
/// <param name="cmd"></param>
/// <returns></returns>
public bool SetValue(string cmd)
{
try
{
while (!(Monitor.TryEnter(obj)))
{
//线程锁占用,等待后再次进入while循环
Thread.Sleep(10);
}
serialPortHelper.SendString(cmd);
string receive = serialPortHelper.ReadToStr("\r");
if (receive == "CMD:REPLY=1@0")
{
return true;
}
return false;
}
catch (Exception ex)
{
return false;
}
finally
{
Monitor.Exit(obj); //线程锁释放
}
}
/// <summary>
/// 查询当前温度
/// </summary>
public double QueryCurrTemp()
{
try
{
while (!(Monitor.TryEnter(obj)))
{
//线程锁占用,等待后再次进入while循环
Thread.Sleep(10);
}
serialPortHelper.SendString("TC1:TCACTUALTEMP?@0\r");
string currTempStr = serialPortHelper.ReadToStr("\r");
//对接收的数据进行处理
double currTemp = Convert.ToDouble(Regex.Match(currTempStr, @"(?<==).*(?=@)").Value);
return currTemp;
}
catch (Exception)
{
return -999;
}
finally
{
Monitor.Exit(obj);
}
}
代码中串口读写是我写的类,在复制的时候会报错,换成自己的读写类就好了
Monitor.TryEnter(obj)表示,查询现在obj对象是不是锁定的状态,如果是锁定的状态,值就是false,那么就进入这个While循环,等待10ms之后再次查看是否仍然锁定,直到obj解锁
while (!(Monitor.TryEnter(obj)))
{
//线程锁占用,等待后再次进入while循环
Thread.Sleep(10);
}
我这里由于查询周期是50ms,所以我延时设置成了10ms,大家可以把延时设置成100或更多以适应自己的程序。在执行完所有的操作后,将obj的锁释放,这样在等候的其他程序就可以操作串口了。
finally
{
Monitor.Exit(obj); //线程锁释放
}
以上是对单个串口进行加锁,解锁操作,以实现读写的控制,如何控制三个串口同时收发,读取数据,并作为三条曲线显示在同一个Chart控件中,我会找个时间再开一篇文章,感兴趣的朋友可以留言