(XMODEM协议)自旋锁异常报错
互斥锁:
如果说当前拿不到锁,释放CPU资源,阻塞等待,直到锁被释放之后,在去重新拿到锁,同时可以设置阻塞时间,,只等待指定的时间;如果在这段时间内仍未获取到锁,就会停止等待并返回失败,而不是无限期阻塞。
自旋锁:
如果说当前拿不到,不会释放当前CPU资源,循环等待,死等直到拿到锁,有点像是一个while死循环。所以一般使用的时候都会设置添加额外超时逻辑来实现结束死循环,原始自旋锁的最大风险是:如果持有锁的线程因异常(如崩溃、死锁)未释放锁,等待的线程会一直自旋(持续占用 CPU),导致 “CPU 空转”。超时机制能解决这一问题 —— 超过设定时间后,线程可以放弃等待,进行错误处理(如记录日志、重试或切换策略)。
如果等待时间较少,就使用自旋锁,如果等待时间较长就使用互斥锁,自旋锁一般使用在微秒级的等待
并且如果超时等待不了锁,就会出现断言错误。
看一个实际的例子:
esp_err_t esp_xmodem_transport_close(esp_xmodem_handle_t handle)
{if (handle){esp_xmodem_transport_t *p = (esp_xmodem_transport_t *)(handle->transport);if (p->uart_task_handle){vTaskDelete(p->uart_task_handle);p->uart_task_handle = NULL;}if (p->uart_queue){ESP_ERROR_CHECK(uart_driver_delete(p->uart_num));xQueueReset(p->uart_queue);p->uart_queue = NULL;}}return ESP_OK;
}当我进行XMODEM结束之后,会清理掉串口当中的数据,但是这里这个函数就会出现下面的报错
assert failed: spinlock_acquire spinlock.h:142 (lock->count == 0)问题出现在xQueueReset(p->uart_queue);这个函数的调用上面,在清理串口资源art_driver_delete(p->uart_num)的时候,已经将清楚串口队列的操作执行了,并且清除串口队列任务使用了自旋锁,当自旋锁没有被释放掉的时候,等待其他任务释放自旋锁,如果超过了等待时间,程序崩溃。像这样的更改方法最好就是将多余的重置队列任务清除掉。
esp_err_t esp_xmodem_transport_close(esp_xmodem_handle_t handle)
{if (handle){esp_xmodem_transport_t *p = (esp_xmodem_transport_t *)(handle->transport);if (p->uart_task_handle){vTaskDelete(p->uart_task_handle);p->uart_task_handle = NULL;}if (p->uart_queue){ESP_ERROR_CHECK(uart_driver_delete(p->uart_num));p->uart_queue = NULL;}}return ESP_OK;
}