linux互斥锁简介(内核态)

本文介绍了互斥锁的概念、数据结构及使用方法,并对比了互斥锁与信号量、自旋锁的区别,帮助读者理解何时选用互斥锁。

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

一、什么是互斥锁
    1、概念
        互斥锁(Mutex)是在原子操作API的基础上实现的信号量行为。互斥锁不能进行递归锁定或解锁,能用于交互上下文但是不能用于中断上下文,同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。当无法获取锁时,线程进入睡眠等待状态。
        互斥锁是信号量的特例。信号量的初始值表示有多少个任务可以同时访问共享资源,如果初始值为1,表示只有1个任务可以访问,信号量变成互斥锁(Mutex)。但是互斥锁和信号量又有所区别,互斥锁的加锁和解锁必须在同一线程里对应使用,所以互斥锁只能用于线程的互斥;信号量可以由一个线程释放,另一个线程得到,所以信号量可以用于线程的同步。
    2、数据结构
struct mutex {
	/* 1: unlocked, 0: locked, negative: locked, possible waiters */
	atomic_t		count;
	spinlock_t		wait_lock;
	struct list_head	wait_list;
#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER)
	struct task_struct	*owner;
#endif
#ifdef CONFIG_MUTEX_SPIN_ON_OWNER
	struct optimistic_spin_queue osq; /* Spinner MCS lock */
#endif
#ifdef CONFIG_DEBUG_MUTEXES
	void			*magic;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map	dep_map;
#endif
};
        结构体成员说明:
        1、atomic_t count;
        指示互斥锁的状态:1 没有上锁,可以获得;0 被锁定,不能获得。初始化为没有上锁。
        2、spinlock_t wait_lock;
        等待获取互斥锁中使用的自旋锁。在获取互斥锁的过程中,操作会在自旋锁的保护中进行。初始化为为锁定。
        3、struct list_head wait_list;
        等待互斥锁的进程队列。

二、如何使用互斥锁
    1、初始化
        mutex_init(&mutex); //动态初始化互斥锁
        DEFINE_MUTEX(mutexname); //静态定义和初始化互斥锁
    2、上锁
        void mutex_lock(struct mutex *lock);
        无法获得锁时,睡眠等待,不会被信号中断。
        int mutex_trylock(struct mutex *lock);
        此函数是 mutex_lock()的非阻塞版本,成功返回1,失败返回0。
        int mutex_lock_interruptible(struct mutex *lock);
        和mutex_lock()一样,也是获取互斥锁。在获得了互斥锁或进入睡眠直到获得互斥锁之后会返回0。如果在等待获取锁的时候进入睡眠状态收到一个信号(被信号打断睡眠),则返回_EINIR。
    3、解锁
        void mutex_unlock(struct mutex *lock);

三、什么时候使用互斥锁
    1、互斥锁和信号量比较
        a、互斥锁功能上基本与二元信号量一样,但是互斥锁占用空间比信号量小,运行效率比信号量高。所以,如果要用于线程间的互斥,优先选择互斥锁。
    2、互斥锁和自旋锁比较
        a、互斥锁在无法得到资源时,内核线程会进入睡眠阻塞状态,而自旋锁处于忙等待状态。因此,如果资源被占用的时间较长,使用互斥锁较好,因为可让CPU调度去做其它进程的工作。
        b、如果被保护资源需要睡眠的话,那么只能使用互斥锁或者信号量,不能使用自旋锁。而互斥锁的效率又比信号量高,所以这时候最佳选择是互斥锁。
        c、中断里面不能使用互斥锁,因为互斥锁在获取不到锁的情况下会进入睡眠,而中断是不能睡眠的。
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、付费专栏及课程。

余额充值