元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
进程管理
▶
进程调度
调度策略
完全公平调度器
实时调度机制
▶
进程通信
信号机制
共享内存
管道与命名管道
▶
进程状态
上下文切换
僵尸进程处理
进程生命周期
▶
内存管理
▶
虚拟内存
页表机制
地址空间布局
TLB管理
▶
物理内存
伙伴系统
slab分配器
内存碎片处理
▶
文件系统
▶
VFS抽象层
inode机制
文件描述符
挂载机制
▶
具体文件系统
Ext4日志机制
Btrfs特性
Proc文件系统
▶
设备驱动
▶
驱动模型
设备树解析
sysfs接口
热插拔处理
▶
网络栈
▶
协议栈架构
sk_buff结构
Netfilter框架
套接字实现
▶
内核同步机制
▶
锁机制
自旋锁实现
RCU机制
Mutex与信号量
▶
启动过程
▶
引导阶段
GRUB交互
内核解压缩
早期初始化
▶
系统调用
▶
调用机制
陷入门实现
vsyscall优化
安全审计
▶
虚拟化和容器支持
▶
容器技术
命名空间隔离
cgroups实现
OverlayFS原理
发布时间:
2025-03-23 11:08
↑
☰
# Linux Mutex与信号量机制 ## 概述 Mutex(互斥锁)和信号量(Semaphore)是Linux内核中的两种重要的同步机制,它们通过让进程进入睡眠状态来实现对共享资源的互斥访问。与自旋锁不同,这两种机制适用于可能长时间持有锁的场景。 ## 基本原理 ### 1. Mutex结构 ```c struct mutex { atomic_t count; spinlock_t wait_lock; struct list_head wait_list; #ifdef CONFIG_DEBUG_MUTEXES struct task_struct *owner; int magic; #endif }; ``` ### 2. 信号量结构 ```c struct semaphore { raw_spinlock_t lock; unsigned int count; struct list_head wait_list; }; ``` ### 3. 工作原理 1. **Mutex** - 只允许一个任务持有 - 必须由加锁者释放 - 不能递归加锁 - 支持优先级继承 2. **信号量** - 支持多个任务并发访问 - 可以由其他任务释放 - 允许递归加锁 - 不支持优先级继承 ## 实现机制 ### 1. Mutex实现 ```c void mutex_lock(struct mutex *lock) { might_sleep(); if (!__mutex_trylock_fast(lock)) __mutex_lock_slowpath(lock); } static __always_inline bool __mutex_trylock_fast(struct mutex *lock) { unsigned long curr = (unsigned long)current; if (atomic_long_try_cmpxchg_acquire(&lock->owner, 0UL, curr)) return true; return false; } void mutex_unlock(struct mutex *lock) { if (__mutex_unlock_fast(lock)) return; __mutex_unlock_slowpath(lock); } ``` ### 2. 信号量实现 ```c void down(struct semaphore *sem) { unsigned long flags; raw_spin_lock_irqsave(&sem->lock, flags); if (likely(sem->count > 0)) sem->count--; else __down(sem); raw_spin_unlock_irqrestore(&sem->lock, flags); } void up(struct semaphore *sem) { unsigned long flags; raw_spin_lock_irqsave(&sem->lock, flags); if (likely(list_empty(&sem->wait_list))) sem->count++; else __up(sem); raw_spin_unlock_irqrestore(&sem->lock, flags); } ``` ### 3. 等待队列 ```c struct mutex_waiter { struct list_head list; struct task_struct *task; struct ww_acquire_ctx *ww_ctx; #ifdef CONFIG_DEBUG_MUTEXES void *magic; #endif }; static void __sched __mutex_lock_slowpath(struct mutex *lock) { struct mutex_waiter waiter; struct task_struct *task = current; waiter.task = task; waiter.ww_ctx = NULL; spin_lock(&lock->wait_lock); list_add_tail(&waiter.list, &lock->wait_list); spin_unlock(&lock->wait_lock); for (;;) { if (mutex_trylock(lock)) break; schedule(); } } ``` ## 使用场景 ### 1. Mutex使用 ```c static DEFINE_MUTEX(my_mutex); static int shared_data; void update_data(int new_value) { mutex_lock(&my_mutex); /* 临界区操作 */ shared_data = new_value; mutex_unlock(&my_mutex); } int read_data(void) { int value; mutex_lock(&my_mutex); /* 临界区操作 */ value = shared_data; mutex_unlock(&my_mutex); return value; } ``` ### 2. 信号量使用 ```c static DEFINE_SEMAPHORE(my_sem); static struct list_head resource_list; void process_resource(void) { down(&my_sem); /* 访问共享资源 */ list_add(&new_resource->list, &resource_list); up(&my_sem); } void cleanup_resource(void) { down(&my_sem); /* 清理资源 */ list_del(&resource->list); up(&my_sem); } ``` ## 性能优化 ### 1. 快速路径 ```c static __always_inline bool __mutex_trylock_fast(struct mutex *lock) { unsigned long curr = (unsigned long)current; if (atomic_long_try_cmpxchg_acquire(&lock->owner, 0UL, curr)) return true; return false; } ``` ### 2. 自适应自旋 ```c static bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner) { bool ret = true; rcu_read_lock(); while (lock->owner == owner) { if (!owner->on_cpu) { ret = false; break; } cpu_relax(); } rcu_read_unlock(); return ret; } ``` ### 3. 优先级继承 ```c static void adjust_priority(struct mutex *lock, struct task_struct *task) { if (task->normal_prio > current->normal_prio) { /* 提升持有锁的任务优先级 */ rt_mutex_setprio(task, current->normal_prio); } } ``` ## 调试技巧 ### 1. 死锁检测 ```c #ifdef CONFIG_DEBUG_MUTEXES static void debug_mutex_lock_common(struct mutex *lock) { if (WARN_ON_ONCE(lock->magic != MUTEX_DEBUG_MAGIC)) return; if (WARN_ON_ONCE(lock->owner == current)) return; } #endif ``` ### 2. 锁依赖 ```bash # 启用lockdep echo 1 > /proc/sys/kernel/lockdep_stats # 查看锁依赖图 cat /proc/lockdep # 检查死锁 cat /proc/lockdep_chains ``` ### 3. 性能分析 ```bash # 使用perf分析锁竞争 perf lock record ./program perf lock report # 查看等待时间 cat /proc/lock_stat ``` ## 最佳实践 1. **选择原则** - 短期锁使用自旋锁 - 长期锁使用mutex - 多任务共享使用信号量 2. **使用规范** - 避免递归加锁 - 保持加锁顺序一致 - 最小化临界区 3. **错误处理** - 处理加锁失败 - 确保正确释放 - 避免死锁情况 ## 常见问题 ### 1. 死锁问题 - 循环等待 - 重复加锁 - 锁顺序错误 ### 2. 性能问题 - 锁粒度过大 - 临界区过长 - 频繁加解锁 ### 3. 使用错误 - 在中断上下文使用mutex - 在持有自旋锁时获取mutex - 错误的锁类型选择 ## 总结 Mutex和信号量是Linux内核中重要的同步机制,它们通过让进程进入睡眠状态来实现对共享资源的保护。理解这两种机制的工作原理和使用场景对于开发高质量的内核代码至关重要。合理使用这些同步机制可以有效地解决并发访问问题。 ## 参考资源 1. Linux内核源码: kernel/locking/mutex.c 2. [Linux内核同步机制](https://www.kernel.org/doc/html/latest/locking/) 3. [Mutex vs Semaphore](https://www.kernel.org/doc/Documentation/locking/mutex-design.txt)