上篇文章介绍了串口遇到的传参问题,今天这篇文章将介绍串口缓存的互斥锁释放问题。
2、 互斥锁释放顺序
现在考虑第二个问题:互斥锁释放顺序问题。
如果没有采用队列方式接收数据,而是主机发送完成后等待接收从机数据后再发送下一帧数据,那么该如何处理互斥锁的问题?
我们知道为了保证数据的同步,保证在接收到一帧数据进行处理时,不能被新的数据帧冲掉,这时就要加入一个互斥锁,表示我正在处理数据,下面的数据我接收不了,这样就能保证你正在处理的数据不会被新来的数据修改掉,从而进行正确的处理。
那么这个标志位(互斥锁)该什么时候清掉(释放掉)呢?
一般来说标志位,一般越早清掉越好,比如外部中断标志位,进入中断后,一般首先会清理标志位,这样即使你正在处理本次中断的程序,那么即使这时再来了中断,也不会丢失中断信息(有悬起标志位),这样就可以在处理完这次中断后,立马进行下一次中断的处理了(前提是优先级足够高)。
但是如果你清理太早或者清理太晚会怎样?
比如说你在接收到一帧数据后(数据帧所有检查完成),开始设置标志位,当主程序查询到这个标志时(一般数据处理不会放在中断中),如果马上开始清除这个标志……嗯,一般来说不会有问题。
那么什么时候会出现问题?当你的主程序查询到这这个标志时开始清除标志,然后处理、返回数据给主机,如果此时主机超时重发数据时,,因为这个时候你虽然在处理数据,但是因为你的标志位已经被清除了,所以接收程序就会开始往接收缓存区存数据了,当你存完之后再回到数据处理那里,你的缓存区可能就不是你想要的数据了。
可能你会说,既然是重发,那么数据应该是相同的吧?好吧,你赢了,鱼鹰编不下去了,这种情况(有重发机制)下清理太早好像是不会出现问题,但你怎么知道对方是采用副本进行重发数据的呢,如果重发时它又从源数据中拷贝后再进行重发会出现什么问题?比如时间信息,开始第一帧数据是 11:59,CPU 刚把 11 拷贝到用户空间,被串口中断程序打断,导致下一帧接收的数据是 12:00,此时回到主程序继续拷贝,拷贝 00,数据的完整性被破坏,这样导致的结果就是 11:00,而实际上时间是 12:00,这就是你打断数据处理过程的后果。
现在再说说清理太晚会怎么样。
当你的主程序查询到这个标志后,暂时不清除,而是等到从机发送完应答数据之后再清除标志,此时因为从机采用查询方式(查询方式表明从机发送完最后一个字节后后开始清除标志位,也就代表了主机就差最后一个字节没有接收了,这样发送和清除之间间隔时间较短,而采用 DMA 方式的话,发送和清除的间隔时间更短,因为可能 DMA 还没开始发送第一帧数据,清除工作就已经完成了),或者因为其他原因(比如中断处理)导致发送和清除之间的时间很长这种特殊情况,这样可能主机已经开始下发下一帧数据了,但是因为此时标志还没有清除,不能接收数据,所以主机这一帧数据就这样丢失了。
那么这个清除标志位最合适的时机是什么时候?
你锁定资源利用完的时候。
现在来看看,这个互斥锁锁定的是什么资源?对,就是接收缓存,那么接收缓存什么时候用完?当然是在数据处理完成之时。也就是说在数据处理完之前、发送数据之前清除最合适。
这样就不会因为处理其他事情而导致清除操作过晚而丢失下一帧数据了,因为此时主机还没收到从机上传的数据,也就不会马上开始下一帧数据的传输了。
说到清除,你觉得,需要把整个缓冲区进行清零操作吗?这个问题在以往的文章解释过,就看你是否看完了。
下集精彩,串口数据帧的检查,喜欢的话,记得关注鱼鹰哦!