鸿蒙南向开发教程 Day 7 附录:互斥锁深度解析

发布时间:2026/6/4 16:33:09

鸿蒙南向开发教程 Day 7 附录:互斥锁深度解析 目标深入理解互斥锁的设计原理、使用场景、常见问题及解决方案一、什么是互斥锁Mutex1.1 核心概念互斥锁Mutual Exclusion Lock是一种用于保护临界资源的同步机制确保同一时刻只有一个线程可以访问被保护的资源。┌─────────────────────────────────────────┐ │ 临界资源Critical Resource │ │ 全局变量、共享缓冲区、硬件寄存器等 │ ├─────────────────────────────────────────┤ │ ┌─────────┐ ┌─────────┐ ┌─────┐ │ │ │ Thread1 │ │ Thread2 │ │ ... │ │ │ └────┬────┘ └────┬────┘ └──┬──┘ │ │ │ │ │ │ │ └──────────────┼────────────┘ │ │ ↓ │ │ ┌─────────────┐ │ │ │ Mutex │ │ │ │ [Locked] │ ← 只有一个 │ │ │ [Unlocked] │ 线程通过 │ │ └─────────────┘ │ └─────────────────────────────────────────┘1.2 为什么叫互斥互相互排斥斥排斥其他线程锁锁定资源禁止他人访问本质对临界资源的访问权进行排队管理。二、互斥锁 vs 其他同步机制机制核心功能使用场景特点Mutex互斥锁资源独占访问保护共享变量、数据结构所有权、递归、优先级继承Semaphore信号量资源计数管理控制并发数量、生产者-消费者无所有权、可多个线程获取Event Flags事件标志事件通知同步多条件组合等待、任务触发32位标志位、AND/OR等待RWLock读写锁读共享写独占读多写少场景读并发、写互斥关键区别Mutex 有所有权Semaphore 没有Mutex只有获取锁的线程才能释放锁Semaphore任何线程都可以释放增加计数不记录谁获取的三、互斥锁的核心特性3.1 所有权Ownership// Thread A 获取锁osMutexAcquire(mid,osWaitForever);// Thread A 成为 Owner// 只有 Thread A 能释放osMutexRelease(mid);// ✅ 正确// Thread B 尝试释放osMutexRelease(mid);// ❌ 错误返回 osErrorResource设计目的防止误释放确保锁的配对使用。3.2 递归锁定Recursive Lockingvoidfunc_a(osMutexId_tmid){osMutexAcquire(mid,osWaitForever);// 第1次获取计数1// ... 访问资源 ...func_b(mid);// 调用 func_bosMutexRelease(mid);// 计数减到0真正释放}voidfunc_b(osMutexId_tmid){osMutexAcquire(mid,osWaitForever);// 第2次获取同一线程计数2// ... 访问资源 ...osMutexRelease(mid);// 计数减到1未真正释放}递归锁特性同一线程可多次获取同一锁获取次数 释放次数 时才真正解锁防止同一线程内部死锁3.3 优先级继承Priority Inheritance优先级反转问题高优先级线程 H优先级 3 中优先级线程 M优先级 5 低优先级线程 L优先级 7持有 Mutex 执行顺序 1. L 获取锁开始执行 2. H 就绪抢占 CPU尝试获取锁 → 阻塞等待 L 释放 3. M 就绪优先级比 L 高抢占 CPU 4. M 执行完毕L 继续执行释放锁 5. H 终于获取锁开始执行 问题H 被 M 间接阻塞M 不需要锁却阻碍了 H。 这叫优先级反转——高优先级线程被低优先级线程阻塞。优先级继承解决方案当 H 阻塞等待 L 的锁时 L 的临时优先级提升到 H 的级别优先级 3 执行顺序变为 1. L 获取锁开始执行优先级 7 2. H 就绪尝试获取锁 → 阻塞 3. L 的优先级提升到 3继承 H 的优先级 4. M 就绪但优先级 5 L 的 3无法抢占 5. L 执行完毕释放锁优先级恢复 7 6. H 获取锁立即执行 7. H 执行完毕M 执行 结果M 无法阻碍 H优先级反转消除LiteOS-M 的互斥锁默认支持优先级继承。四、互斥锁的使用规范4.1 黄金法则法则说明成对使用每个Acquire必须有对应的Release最小临界区锁保护的代码越短越好减少竞争禁止阻塞操作临界区内不能调用osDelay、I/O 等阻塞函数避免嵌套过多嵌套锁增加死锁风险设计时尽量减少先获取后释放顺序多个锁时所有线程按相同顺序获取4.2 错误示例死锁osMutexId_tm1,m2;// Thread Avoidthread_a(void){osMutexAcquire(m1,osWaitForever);// 获取 m1osDelay(1);// 模拟工作osMutexAcquire(m2,osWaitForever);// 尝试获取 m2 → 阻塞等待 B 释放 m2// ... 永远不会执行到这里 ...osMutexRelease(m2);osMutexRelease(m1);}// Thread Bvoidthread_b(void){osMutexAcquire(m2,osWaitForever);// 获取 m2osDelay(1);osMutexAcquire(m1,osWaitForever);// 尝试获取 m1 → 阻塞等待 A 释放 m1// ... 永远不会执行到这里 ...osMutexRelease(m1);osMutexRelease(m2);}// 结果A 等 m2B 等 m1互相等待永久阻塞 死锁死锁条件Coffman 四条件互斥资源独占持有并等待持有锁同时等待其他锁不可抢占锁不能被强制释放循环等待形成等待环路预防方法所有线程按相同顺序获取锁如都先 m1 后 m2。4.3 正确示例成对使用 最小临界区voidcorrect_usage(osMutexId_tmid){// 准备数据不需要锁intlocal_datacompute_something();// 获取锁osMutexAcquire(mid,osWaitForever);// 临界区只放必要的共享资源访问g_shared_valuelocal_data;g_shared_count;// 立即释放osMutexRelease(mid);// 后续处理不需要锁printf(Done\n);}五、互斥锁在 OpenHarmony 中的实现细节5.1 数据结构LiteOS-M 互斥锁控制块简化typedefstruct{UINT8 ucMuxStat;// 锁状态OS_MUX_USED / OS_MUX_UNUSEDUINT16 usMuxCount;// 递归计数递归锁次数UINT32 uxMuxID;// 锁 IDLOS_DL_LIST stMuxList;// 等待队列阻塞的线程链表LOS_TASK_CB*pstOwner;// 所有者任务控制块指针UINT16 usPriority;// 所有者原始优先级用于优先级恢复}LOS_MUX_CB;5.2 状态转换图┌─────────┐ osMutexNew() ┌─────────┐ osMutexAcquire() ┌─────────┐ │ 未创建 │ ──────────────→ │ 空闲 │ ────────────────────→ │ 锁定 │ │ (NULL) │ │(Unlocked)│ 无竞争立即获取 │ (Locked)│ └─────────┘ └─────────┘ 有竞争加入等待队列 └────┬────┘ ↑ │ └────────────────────────────────────┘ osMutexRelease() 唤醒等待队列首个线程 或变为空闲5.3 等待队列管理等待队列优先级排序 ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ T3 │ → │ T5 │ → │ T7 │ → │ T9 │ → NULL │ prio│ │ prio│ │ prio│ │ prio│ │ 3 │ │ 5 │ │ 7 │ │ 9 │ └─────┘ └─────┘ └─────┘ └─────┘ 最高优先级 最低优先级 释放锁时唤醒 T3队首优先级最高LiteOS-M 使用优先级队列管理等待线程确保高优先级线程优先获取锁。六、常见问题排查现象原因排查方法程序卡死死锁检查osMutexGetOwner看哪个线程持有锁不释放数据异常未加锁保护检查所有访问共享变量的位置是否都有Acquire/Release优先级反转高优先级线程被低优先级阻塞确认 LiteOS 优先级继承是否启用返回 osErrorResource非所有者释放确认释放线程与获取线程是否为同一个递归获取失败超出最大递归深度检查递归调用层次或改用普通锁七、总结要点内容核心功能保护临界资源确保独占访问关键特性所有权、递归锁定、优先级继承使用规范成对使用、最小临界区、禁止阻塞操作死锁预防统一获取顺序、超时机制、避免嵌套底层实现LiteOS-MLOS_MUX_CB控制块 优先级等待队列与信号量区别Mutex 有所有权Semaphore 无所有权八、下一步Day 8 预告信号量Semaphore—— 资源计数与多任务同步。需要继续 Day 8 的内容吗

相关新闻