kernel互斥锁mutex

本文介绍了内核互斥锁的基本概念及其实现原理。详细解释了互斥锁的结构体成员及其作用,并列举了互斥锁的主要API,包括初始化、获取、尝试获取和释放等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

互斥锁主要用于实现内核中的互斥访问功能。内核互斥锁是在原子 API 之上实现的,但这对于内核用户是不可见的。对它的访问必须遵循一些规则:同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。互斥锁不能进行递归锁定或解锁。一个互斥锁对象必须通过其API初始化,一个任务在持有互斥锁的时候是不能结束的,互斥锁所使用的内存区域是不能被释放的,使用中的互斥锁是不能被重新初始化的,并且互斥锁不能用于中断上下文。互斥锁比内核信号量更快,并且更加紧凑,因此如果它们满足您的需求,那么它们将是您明智的选择。

/linux/include/linux/mutex.h

struct mutex {
          /* 1: unlocked, 0: locked, negative: locked, possible waiters */
          atomic_t                count;
          spinlock_t              wait_lock;
          struct list_head        wait_list;
  #ifdef CONFIG_DEBUG_MUTEXES
          struct thread_info      *owner;
          const char              *name;
          void                    *magic;
  #endif
  #ifdef CONFIG_DEBUG_LOCK_ALLOC
          struct lockdep_map      dep_map;
  #endif
  };

count指示互斥锁的状态:

     1 没有上锁,可以获得
     0 被锁定,不能获得
     负数 被锁定,且可能在该锁上有等待进程,初始化为没有上锁。

wait_lock等待获取互斥锁时使用的自旋锁。在获取互斥锁的过程中,操作会在自旋锁的保护中进行。初始化为为锁定。

wait_list等待互斥锁的进程队列。


相关API:

1、定义并初始化:

struct mutex mutex;

mutex_init(&mutex);

2、获取互斥锁:

(1)具体参见linux/kernel/mutex.c

void inline fastcall __sched mutex_lock(struct mutex *lock);
首先取得count的值,在将count置-1,判断如果原来count的置为1,也即互斥锁可以获得,则直接获取然后跳出。否则进入循环反复测试互斥锁的状态。在循环中,同样先取得互斥锁原来的状态,在将其-1,如果可以获取(等于1),则退出循环,否则设置当前进程的状态为不可中断状态,解锁自身的自旋锁,进入睡眠状态,待被再调度唤醒时,再获得自身的自旋锁,进入新一次的查询其自身状态(该互斥锁的状态)的循环。


(2)具体参见linux/kernel/mutex.c

int fastcall __sched mutex_lock_interruptible(struct mutex *lock);

和mutex_lock()一样,在获得了互斥锁后会返回0。如果在等待获取锁的时候进入睡眠状态并收到一个信号(被信号打断睡眠),则返回-EINIR。


(3)具体参见linux/kernel/mutex.c

int fastcall __sched mutex_trylock(struct mutex *lock);

试图获取互斥锁,如果成功获取则返回1,否则返回0,不等待。


3、释放互斥锁:

具体参见linux/kernel/mutex.c

void fastcall mutex_unlock(struct mutex *lock);

释放被当前进程获取的互斥锁。该函数不能用在中断上下文中,而且不允许去释放一个没有上锁的互斥锁。

在Linux内核中,互斥锁mutex)是一种用于保护共享资源的同步机制。与自旋锁(spinlock)不同,互斥锁允许线程在等待锁时进入睡眠状态,因此适用于长时间持有的场景。互斥锁的实现和使用方式在内核中经过了优化,以确保高效性和正确性。 ### 互斥锁的定义和初始化 互斥锁的结构体定义如下: ```c struct mutex { atomic_long_t owner; spinlock_t wait_lock; struct list_head wait_list; }; ``` - `owner`:记录当前持有互斥锁的线程信息。 - `wait_lock`:保护等待队列的自旋锁。 - `wait_list`:等待该互斥锁的线程列表。 互斥锁可以通过以下宏进行静态初始化: ```c DEFINE_MUTEX(name); ``` 或者通过动态初始化函数: ```c void mutex_init(struct mutex *lock); ``` ### 互斥锁的基本操作 #### 获取互斥锁 获取互斥锁的操作通常使用 `mutex_lock()` 函数: ```c void mutex_lock(struct mutex *lock); ``` 此函数会尝试获取指定的互斥锁,如果锁已经被占用,则调用线程将被放入等待队列并进入睡眠状态,直到锁可用。 #### 尝试获取互斥锁 如果你希望在不阻塞的情况下尝试获取互斥锁,可以使用 `mutex_trylock()` 函数: ```c int mutex_trylock(struct mutex *lock); ``` 该函数返回值为1表示成功获取锁,0表示锁已被占用。 #### 释放互斥锁 释放互斥锁的操作使用 `mutex_unlock()` 函数: ```c void mutex_unlock(struct mutex *lock); ``` 此函数会唤醒等待队列中的第一个线程(如果有),使其有机会获取锁。 ### 示例代码 下面是一个简单的示例,展示了如何在Linux内核模块中使用互斥锁来保护共享资源: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/mutex.h> static DEFINE_MUTEX(my_mutex); // 定义并初始化一个互斥锁 static int shared_resource = 0; static void access_shared_resource(void) { mutex_lock(&my_mutex); // 获取互斥锁 shared_resource++; printk(KERN_INFO "Shared resource value: %d\n", shared_resource); mutex_unlock(&my_mutex); // 释放互斥锁 } static int __init my_module_init(void) { printk(KERN_INFO "Module loaded\n"); access_shared_resource(); return 0; } static void __exit my_module_exit(void) { printk(KERN_INFO "Module unloaded\n"); } module_init(my_module_init); module_exit(my_module_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("A simple Linux kernel module using mutex"); ``` 在这个示例中,`access_shared_resource()` 函数通过互斥锁保护对 `shared_resource` 的访问。当多个线程同时调用这个函数时,互斥锁确保每次只有一个线程能够修改 `shared_resource` 的值。 ### 互斥锁的特点 - **睡眠特性**:与自旋锁不同,互斥锁允许等待线程进入睡眠状态,因此适合于需要较长时间持有的场景。 - **递归锁定**:互斥锁支持递归锁定,即同一个线程可以多次获取同一个互斥锁而不会死锁。但是需要注意解锁次数必须与加锁次数相同。 - **公平性**:互斥锁的实现通常是公平的,即等待时间最长的线程优先获得锁。 ### 注意事项 - **避免死锁**:在使用互斥锁时,务必注意避免死锁的情况。例如,两个线程分别持有一个锁并试图获取对方的锁会导致死锁。 - **上下文切换开销**:由于互斥锁可能导致线程进入睡眠状态,因此频繁的锁竞争可能会导致较高的上下文切换开销。 通过合理使用互斥锁,可以在Linux内核中有效地保护共享资源,确保多线程环境下的数据一致性。[^4] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值