多线程开发常见问题

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_NORMALQOSA_PRIORITY_LOW

  • 不要轻易把业务线程拉到 QOSA_PRIORITY_REALTIMEQOSA_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. 需要耗时处理时,复制必要数据后尽快解锁。