1(_mutex_doc)= 2 3:::{note} 4作者:龙进 <longjin@RinGoTek.cn> 5::: 6 7# mutex互斥量 8 9  mutex是一种轻量级的同步原语,只有被加锁、空闲两种状态。 10 11  当mutex被占用时,尝试对mutex进行加锁操作的进程将会被休眠,直到资源可用。 12 13## 1. 特性 14 15- 同一时间只有1个任务可以持有mutex 16- 不允许递归地加锁、解锁 17- 只允许通过mutex的api来操作mutex 18- 在硬中断、软中断中不能使用mutex 19 20## 2. 定义 21 22  mutex定义在`lib/mutex.rs`中,定义如下所示: 23 24```rust 25/// @brief Mutex互斥量结构体 26/// 请注意!由于Mutex属于休眠锁,因此,如果您的代码可能在中断上下文内执行,请勿采用Mutex! 27#[derive(Debug)] 28pub struct Mutex<T> { 29 /// 该Mutex保护的数据 30 data: UnsafeCell<T>, 31 /// Mutex内部的信息 32 inner: SpinLock<MutexInner>, 33} 34 35#[derive(Debug)] 36struct MutexInner { 37 /// 当前Mutex是否已经被上锁(上锁时,为true) 38 is_locked: bool, 39 /// 等待获得这个锁的进程的链表 40 wait_list: LinkedList<&'static mut process_control_block>, 41} 42 43``` 44 45## 3. 使用 46 47  与SpinLock类似,Rust版本的Mutex具有一个守卫。使用的时候,需要将要被保护的数据的所有权移交Mutex。并且,守卫只能在加锁成功后产生,因此,每个时刻,每个Mutex最多存在1个守卫。 48 49  当需要读取、修改Mutex保护的数据时,请先使用Mutex的`lock()`方法。该方法会返回一个`MutexGuard`。您可以使用被保护的数据的成员函数来进行一些操作。或者是直接读取、写入被保护的数据。(相当于您获得了被保护的数据的可变引用) 50 51  完整示例如下方代码所示: 52 53```rust 54let x :Mutex<Vec<i32>>= Mutex::new(Vec::new()); 55 { 56 let mut g :MutexGuard<Vec<i32>>= x.lock(); 57 g.push(1); 58 g.push(2); 59 g.push(2); 60 assert!(g.as_slice() == [1, 2, 2] || g.as_slice() == [2, 2, 1]); 61 // 在此处,Mutex是加锁的状态 62 debug!("x={:?}", x); 63 } 64 // 由于上方的变量`g`,也就是Mutex守卫的生命周期结束,自动释放了Mutex。因此,在此处,Mutex是放锁的状态 65 debug!("x={:?}", x); 66``` 67 68  对于结构体内部的变量,我们可以使用Mutex进行细粒度的加锁,也就是使用Mutex包裹需要细致加锁的成员变量,比如这样: 69 70```rust 71pub struct a { 72 pub data: Mutex<data_struct>, 73} 74``` 75 76  当然,我们也可以对整个结构体进行加锁: 77 78```rust 79struct MyStruct { 80 pub data: data_struct, 81} 82/// 被全局加锁的结构体 83pub struct LockedMyStruct(Mutex<MyStruct>); 84``` 85 86## 4. API 87 88### 4.1. new - 初始化Mutex 89 90#### 原型 91 92```rust 93pub const fn new(value: T) -> Self 94``` 95 96#### 说明 97 98  `new()`方法用于初始化一个Mutex。该方法需要一个被保护的数据作为参数。并且,该方法会返回一个Mutex。 99 100 101### 4.2. lock - 加锁 102 103#### 原型 104 105```rust 106pub fn lock(&self) -> MutexGuard<T> 107``` 108 109#### 说明 110 111  对Mutex加锁,返回Mutex的守卫,您可以使用这个守卫来操作被保护的数据。 112 113  如果Mutex已经被加锁,那么,该方法会阻塞当前进程,直到Mutex被释放。 114 115### 4.3. try_lock - 尝试加锁 116 117#### 原型 118 119```rust 120pub fn try_lock(&self) -> Result<MutexGuard<T>, i32> 121``` 122 123#### 说明 124 125  尝试对Mutex加锁。如果加锁失败,不会将当前进程加入等待队列。如果加锁成功,返回Mutex的守卫;如果当前Mutex已经被加锁,返回`Err(错误码)`。 126 127## 5. C版本的Mutex(在将来会被废弃) 128 129  mutex定义在`common/mutex.h`中。其数据类型如下所示: 130 131```c 132typedef struct 133{ 134 135 atomic_t count; // 锁计数。1->已解锁。 0->已上锁,且有可能存在等待者 136 spinlock_t wait_lock; // mutex操作锁,用于对mutex的list的操作进行加锁 137 struct List wait_list; // Mutex的等待队列 138} mutex_t; 139``` 140 141### 5.1. API 142 143#### mutex_init 144 145**`void mutex_init(mutex_t *lock)`** 146 147  初始化一个mutex对象。 148 149#### mutex_lock 150 151**`void mutex_lock(mutex_t *lock)`** 152 153  对一个mutex对象加锁。若mutex当前被其他进程持有,则当前进程进入休眠状态。 154 155#### mutex_unlock 156 157**`void mutex_unlock(mutex_t *lock)`** 158 159  对一个mutex对象解锁。若mutex的等待队列中有其他的进程,则唤醒下一个进程。 160 161#### mutex_trylock 162 163**`void mutex_trylock(mutex_t *lock)`** 164 165  尝试对一个mutex对象加锁。若mutex当前被其他进程持有,则返回0.否则,加锁成功,返回1. 166 167#### mutex_is_locked 168 169**`void mutex_is_locked(mutex_t *lock)`** 170 171  判断mutex是否已被加锁。若给定的mutex已处于上锁状态,则返回1,否则返回0。 172