首先是概念
互斥锁是可以休眠的。
所以不能在中断中使用,
在中断中只能使用 自旋锁。
然后是 函数:
然后是 open 如果以 NONBLOCK 打开, 遇到 互斥锁怎么办?
总结一下:
1 open() 函数的 阻塞与不阻塞的标志, 还是要看驱动怎么处理。
2 如果 open 是非阻塞打开的,但是 驱动中 的open 函数, 是 mutex_lock() 那么依然是 阻塞的。
3 驱动中可以 依据 应用的 阻塞与非阻塞的关键字 进行 区别处理。
然后是一个应用的举例。
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/delay.h>
static DEFINE_MUTEX(my_mutex); // 定义互斥体
static int shared_resource = 0; // 共享资源
// 修改共享资源的函数
static void modify_shared_resource(void)
{
mutex_lock(&my_mutex); // 获取互斥体
// 临界区:对共享资源进行修改
printk(KERN_INFO "Modifying shared resource\n");
shared_resource++;
printk(KERN_INFO "Shared resource value: %d\n", shared_resource);
// 模拟一些耗时操作
mdelay(100); // 100 毫秒的延迟
mutex_unlock(&my_mutex); // 释放互斥体
}
static int __init mutex_example_init(void)
{
printk(KERN_INFO "Mutex example module loaded\n");
// 模拟多个线程对共享资源的访问
modify_shared_resource();
modify_shared_resource();
return 0;
}
static void __exit mutex_example_exit(void)
{
printk(KERN_INFO "Mutex example module unloaded\n");
}
module_init(mutex_example_init);
module_exit(mutex_example_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Example Author");
MODULE_DESCRIPTION("A simple example of mutex usage in Linux kernel");
然后是应用层的 Mutex 与 驱动的mutex 的区别。
我在网上见到一个这个函数,
pthread_mutex_lock(&mutex);
那么与驱动的 mutex有什么区别呢?
总结: 就是一个是 posix 的,一个是内核提供的,感觉没有什么区别。
然后是 互斥锁的分析。
直接抄过来 AI解释。
// 定义一个静态内联函数,用于获取互斥锁,包含复杂的参数
static __always_inline int __sched
__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass,
struct lockdep_map *nest_lock, unsigned long ip,
struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx)
{
// 定义一个互斥锁等待者结构体
struct mutex_waiter waiter;
bool first = false; // 标记当前等待者是否是等待队列中的第一个
struct ww_mutex *ww; // 指向ww_mutex的指针
int ret; // 函数返回值
// 表明该函数可能会睡眠(即可能会阻塞)
might_sleep();
// 将lock指针转换为ww_mutex指针
ww = container_of(lock, struct ww_mutex, base);
// 如果使用ww_ctx且ww_ctx非空
if (use_ww_ctx && ww_ctx) {
// 如果ww_ctx与ww的当前上下文相同,则直接返回-EALREADY
if (unlikely(ww_ctx == READ_ONCE(ww->ctx)))
return -EALREADY;
// 如果ww_ctx没有获取任何锁,则重置其wounded标志
if (ww_ctx->acquired == 0)
ww_ctx->wounded = 0;
}
// 禁用抢占
preempt_disable();
// 记录锁依赖关系
mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip);
// 尝试快速获取锁或乐观自旋获取锁
if (__mutex_trylock(lock) ||
mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, NULL)) {
// 成功获取锁
lock_acquired(&lock->dep_map, ip);
if (use_ww_ctx && ww_ctx)
ww_mutex_set_context_fastpath(ww, ww_ctx);
preempt_enable(); // 重新启用抢占
return 0;
}
// 获取锁的等待锁
spin_lock(&lock->wait_lock);
// 再次尝试获取锁
if (__mutex_trylock(lock)) {
if (use_ww_ctx && ww_ctx)
__ww_mutex_check_waiters(lock, ww_ctx);
goto skip_wait; // 跳转到跳过等待的代码段
}
// 调试信息记录
debug_mutex_lock_common(lock, &waiter);
// 记录锁竞争情况
lock_contended(&lock->dep_map, ip);
// 根据是否使用ww_ctx,将等待者添加到等待队列的不同位置
if (!use_ww_ctx) {
__mutex_add_waiter(lock, &waiter, &lock->wait_list);
#ifdef CONFIG_DEBUG_MUTEXES
waiter.ww_ctx = MUTEX_POISON_WW_CTX; // 调试用,标记ww_ctx为无效
#endif
} else {
ret = __ww_mutex_add_waiter(&waiter, lock, ww_ctx);
if (ret)
goto err_early_kill; // 如果添加失败,则跳转到错误处理
waiter.ww_ctx = ww_ctx; // 设置等待者的ww_ctx
}
waiter.task = current; // 设置等待者的任务为当前任务
// 设置当前任务的状态为指定的state(通常是TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE)
set_current_state(state);
for (;;) { // 无限循环,直到成功获取锁或发生错误
if (__mutex_trylock(lock))
goto acquired; // 成功获取锁,跳转到获取锁后的处理代码
// 检查当前任务是否有待处理的信号
if (unlikely(signal_pending_state(state, current))) {
ret = -EINTR; // 如果有信号,则返回-EINTR
goto err; // 跳转到错误处理
}
if (use_ww_ctx && ww_ctx) {
ret = __ww_mutex_check_kill(lock, &waiter, ww_ctx);
if (ret)
goto err; // 如果需要被杀掉,则跳转到错误处理
}
// 释放等待锁,让出CPU
spin_unlock(&lock->wait_lock);
schedule_preempt_disabled();
// 如果是ww_mutex或第一次检查,则更新first标志,并可能设置MUTEX_FLAG_HANDOFF标志
if ((use_ww_ctx && ww_ctx) || !first) {
first = __mutex_waiter_is_first(lock, &waiter);
if (first)
__mutex_set_flag(lock, MUTEX_FLAG_HANDOFF);
}
// 重新设置任务状态,并尝试再次获取锁或自旋等待
set_current_state(state);
if (__mutex_trylock(lock) ||
(first && mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx, &waiter)))
break; // 如果成功获取锁,则跳出循环
// 获取等待锁,准备下一次循环
spin_lock(&lock->wait_lock);
}
spin_lock(&lock->wait_lock); // 确保在修改锁状态前持有等待锁
acquired:
__set_current_state(TASK_RUNNING); // 设置任务状态为运行
if (use_ww_ctx && ww_ctx) {
// 如果是ww_mutex且不是第一个等待者,则检查等待队列中的其他等待者
if (!ww_ctx->is_wait_die &&
!__mutex_waiter_is_first(lock, &waiter))
__ww_mutex_check_waiters(lock, ww_ctx);
}
// 从等待队列中移除等待者,并清理相关状态
mutex_remove_waiter(lock, &waiter, current);
if (likely(list_empty(&lock->wait_list)))
__mutex_clear_flag(lock, MUTEX_FLAGS);
debug_mutex_free_waiter(&waiter); // 释放等待者相关的调试信息
skip_wait:
// 记录锁获取成功
lock_acquired(&lock->dep_map, ip);
if (use_ww_ctx && ww_ctx)
ww_mutex_lock_acquired(ww, ww_ctx); // 如果是ww_mutex,则记录锁获取成功
spin_unlock(&lock->wait_lock); // 释放等待锁
preempt_enable(); // 重新启用抢占
return 0; // 成功获取锁
err:
__set_current_state(TASK_RUNNING); // 设置任务状态为运行
mutex_remove_waiter(lock, &waiter, current); // 从等待队列中移除等待者
err_early_kill:
spin_unlock(&lock->wait_lock); // 释放等待锁
debug_mutex_free_waiter(&waiter); // 释放等待者相关的调试信息
mutex_release(&lock->dep_map, 1, ip); // 记录锁释放
preempt_enable(); // 重新启用抢占
return ret; // 返回错误码
}