/linux/include/linux/.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
};
二、作用及访问规则:
互斥锁主要用于实现内核中的互斥访问功能,内核互斥锁是在原子 API 之上实现的,但这对于内核用户是不可见的;对它的访问必须遵循一些规则:
1. 同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁;
2. 互斥锁不能进行递归锁定或解锁;
3. 一个互斥锁对象必须通过其API初始化,而不能使用memset或复制初始化;
4. 一个任务在持有互斥锁的时候是不能结束的;
5. 互斥锁所使用的内存区域是不能被释放的;
6. 使用中的互斥锁是不能被重新初始化的;
7. 并且互斥锁不能用于中断上下文;
但是互斥锁比当前的内核信号量选项更快,并且更加紧凑,因此如果它们满足您的需求,那么它们将是您明智的选择。
四、操作:
1、定义并初始化:
struct mutex mutex;
mutex_init(&mutex);
# define mutex_init(mutex) \
do { \
static struct lock_class_key __key; \
__mutex_init((mutex), #mutex, &__key); \
} while (0)
void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
{
atomic_set(&lock->count, 1);
spin_lock_init(&lock->wait_lock);
INIT_LIST_HEAD(&lock->wait_list);
debug_mutex_init(lock, name, key);
}
直接定义互斥锁mutex并初始化为未锁定,count为1,wait_lock为未上锁,等待队列wait_list为空。
2、获取互斥锁:
(1)具体参见linux/kernel/mutex.c
void __sched mutex_lock(struct mutex *lock);
/*
获取互斥锁;实际是给count做自减操作,然后使用本身的自旋锁进入临界区操作;若互斥锁可以获得,则直接获取,跳出;
否则进入循环反复测试互斥锁的状态;获取则退出循环,否则设置当前进程的状态为不可中断状态,解锁自身的自旋锁,进入睡眠状态,待被在调度唤醒时,再获得自身的自旋锁,进入新一次的查询其自身状态(该互斥锁的状态)的循环。
*/
(2)具体参见linux/kernel/mutex.c
int __sched mutex_lock_interruptible(struct mutex *lock);
和mutex_lock()一样,也是获取互斥锁;在获得了互斥锁或进入睡眠直到获得互斥锁之后会返回0;如果在等待获取锁的时候进入睡眠状态收到一个信号(被信号打断睡眠),则返回-EINIR。
(3)具体参见linux/kernel/mutex.c
int __sched mutex_trylock(struct mutex *lock);
试图获取互斥锁,如果成功获取则返回1,否则返回0,不等待。
3、释放互斥锁:
具体参见linux/kernel/mutex.c
void mutex_unlock(struct mutex *lock);
释放被当前进程获取的互斥锁;该函数不能用在中断上下文中,而且不允许去释放一个没有上锁的互斥锁。
五、使用形式:
struct mutex mutex;
mutex_init(&mutex); /*定义*/
...
mutex_lock(&mutex); /*获取互斥锁*/
... /*临界资源*/
mutex_unlock(&mutex); /*释放互斥锁*/