OBJ-C中dispatch_once的用法

见如下代码:

+(GameState*)sharedGameState{
    static GameState *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [GameState new];
    });
    return sharedInstance;
}

首先声明了2个静态(全局)变量。无论你将它们放在方法内部还是外部都没什么关系。它们都被初始化为0(nil)。

sharedInstance存储单例类实例的引用,而onceToken是一个有趣的变量,实际它的数据类型是long。

dispatch_one函数仅仅运行block一次!传入一个指向onceToken的变量。仅仅当onceToken为0时block才会运行,而当dispatch_once运行过block之后,会将onceToken的值改为非零。

### UART_IDLE_IT 中断处理逻辑 在 STM32 的 HAL 库中,`UART_IDLE_IT` 是用于检测串口空闲中断的机制。当接收到的数据流结束时,会触发 `IDLE` 状态标志位,从而进入相应的中断服务程序(ISR)。这种机制非常适合于接收不定长数据的情况。 #### IDLE 中断的核心功能 - 当发生 `IDLE` 中断时,表示当前帧传输已经完成。 - 此时需要停止 DMA 接收操作并保存已接收到的数据长度。 - 随后重新配置 DMA 控制器以准备下一次接收任务。 具体实现如下: 1. **捕获 IDLE 中断事件** - 使用 `__HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_IDLETF)` 清除 IDLE 标志位[^1]。 - 停止当前正在进行中的 DMA 数据传输:调用函数 `HAL_DMA_Abort(&hdma_usartX_rx)` 来终止 DMA 操作[^4]。 2. **获取实际接收到的数据量** - 调用 `__HAL_DMA_GET_COUNTER(&hdma_usartX_rx)` 获取剩余未传输字节数。 - 计算出有效载荷大小为缓冲区总容量减去上述计数值。 ```c // 剩余待传字节的数量 uint16_t remaining_bytes = __HAL_DMA_GET_COUNTER(&hdma_usartX_rx); // 实际接收到的有效字节数 uint16_t received_data_length = BUFFER_SIZE - remaining_bytes; ``` 3. **重置 DMA 并启动新一轮接收过程** - 设置新的目标地址指向环形缓存下一位置。 - 更新写索引(write_index)至最新偏移处以便后续读取解析这些新到达的信息片段。 ```c dma_obj->write_index += received_data_length; if(dma_obj->write_index >= CIRCULAR_BUFFER_MAX){ dma_obj->write_index -= CIRCULAR_BUFFER_MAX; } // 准备好下一个循环接收区域首址赋给DMA控制器参数结构体成员变量MemoryAddress字段. hdma_usartX_rx.Init.Memory0BaseAddr = (uint32_t)(buffer + dma_obj->write_index); // 再次激活DMA引擎继续监听更多可能到来的新消息包. HAL_DMA_Start_IT(&hdma_usartX_rx,(uint32_t)&huartX->DR,(uint32_t)(buffer+dma_obj->write_index),BUFFER_SIZE); ``` 以上步骤确保即使面对未知长度的消息也能被妥善捕捉下来而不会丢失任何部分. --- ### 关于 `dma_obj.write_index` 的计算方法 对于基于双缓冲或者单缓冲模式下的 DMA 循环接收而言,维护一个动态更新的指针至关重要——这就是所谓的 “write index”。它记录着最近刚存储完毕的一批数据末端所在的位置坐标值;每当成功抓取消息之后都会依据此次所接纳到的具体数量来调整该指标向前进相应步数. 假设我们定义了一个最大尺寸为 N 字节的圆形队列作为临时储存空间,则每次新增加 M 字节资料进来的时候: 如果 `(current_write_index + M) < N`, 则简单增加即可; 否则需考虑越界情况做模运算修正回起点附近适当之处再累加上超出的部分距离形成最终定位结果。 ```c dma_obj->write_index += current_received_size; if( dma_obj->write_index >= CIRCULAR_QUEUE_LIMIT ){ dma_obj->write_index %= CIRCULAR_QUEUE_LIMIT ; } ``` 此算法保证无论何时何地都能准确找到最新的可访问起始点供应用程序层进一步分析利用. --- ### 注意事项 尽管这种方法非常高效且灵活适用于多种场景需求,但仍有一些潜在陷阱需要注意规避以免造成系统崩溃或其他不良后果: - 如果连续两次间隔过短以至于前一阶段尚未完全退出就又进入了第二次相同类型的异常状况可能会引起冲突甚至死锁现象因此建议合理安排超时保护措施防止无限等待情形的发生[^2]. - 对于某些特殊情况下比如电源管理期间低功耗状态下唤醒恢复过程中也应特别小心处理各类同步信号关系以防错乱引发不可预期的行为表现出来[^3]. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值