# 多线程开发常见问题 ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- # 任务创建应该用哪个接口? 优先使用: - *qosa_task_create* 在明确需要自管栈和TCB内存时,考虑: - *qosa_task_create_static* 静态创建适合: - 对内存可控性要求很高 - 需要避免动态分配 - 想把线程内存放到指定区域 静态创建有额外约束: - 需要提供 *stackMem* - *tcbMem* 需要满足最小大小和对齐要求 SDK提供了配套查询接口: - *qosa_task_get_tcb_min_size* - *qosa_task_get_tcb_align* # 线程栈多大合适? 建议大小: - QCM monitor task栈:2048 最后根据实际业务调整 # 优先级应该怎么选? 默认档位是: - *QOSA_PRIORITY_REALTIME* = 99 - *QOSA_PRIORITY_HIGH* = 80 - *QOSA_PRIORITY_ABOVE_NORMAL* = 60 - *QOSA_PRIORITY_NORMAL* = 40 - *QOSA_PRIORITY_BELOW_NORMAL* = 20 - *QOSA_PRIORITY_LOW* = 10 - *QOSA_PRIORITY_IDLE* = 1 推荐做法: - 常规业务线程用 *QOSA_PRIORITY_NORMAL* - 对时延敏感但不是中断级别的线程用 *QOSA_PRIORITY_ABOVE_NORMAL* - 后台清理、低频处理线程用 *QOSA_PRIORITY_BELOW_NORMAL* 或 *QOSA_PRIORITY_LOW* - 不要轻易把业务线程拉到 *QOSA_PRIORITY_REALTIME* 或 *QOSA_PRIORITY_HIGH* # 为什么线程创建成功,但系统表现越来越卡? - 高优先级线程里做了阻塞I/O - while死循环里没有等待点 - 反复轮询状态,没有用信号量或消息队列 - 持锁时间太长 - 在中心线程或回调线程里做耗时业务 # 互斥锁、信号量、消息队列、事件标志应该怎么选? ## 互斥锁 适合保护共享资源,例如: - 全局链表 - 会话表 - 状态机上下文 - 文件句柄集合 ## 信号量 适合做同步通知,例如: - 一个线程等另一个线程完成初始化 - 中断或回调通知工作线程继续处理 SDK注释里对 *qosa_sem_create* 的建议明确: - *initialCount* 通常设为 0 ## 消息队列 适合跨线程传递事件和数据。 例如socket、NTP、MQTT、WebSocket、DTLS重传。 ## 事件标志 - 等任一事件发生 - 等全部事件准备完成 # 为什么消息队列发送会失败? *qosa_msgq_release* 头文件里已经明确说明: - 队列满时,发布可能失败并返回负值 高频错误场景: - 使用 *QOSA_NO_WAIT* 发送,但消费者处理不过来 - 队列深度太小 - 消费线程被更高优先级线程长期压制 - 把大对象当消息反复投递,处理路径太慢 建议: 1. 高频路径优先只投递轻量事件结构。 2. 根据峰值流量合理放大 *maxNumber*。 3. 对关键消息检查返回值,不能默认忽略。 4. 如果发送方不能阻塞,要设计丢弃策略和统计日志。 # 为什么加锁后会死锁? ## 忘记解锁 - lock后中途return - lock后goto error,但error分支没unlock ## 锁顺序不一致 - 线程A先拿lock1再拿lock2 - 线程B先拿lock2再拿lock1 ## 持锁做耗时操作 - 网络收发 - 文件读写 - AT命令等待 - 大块内存处理 ## 在回调或中心线程里嵌套等待 看起来只是“等一下结果”,实际可能把系统关键线程卡死。 建议: 1. 全项目统一锁顺序。 2. 持锁区只做最小状态修改。 3. 需要耗时处理时,复制必要数据后尽快解锁。