互斥锁是实现传统互斥锁的内核对象。互斥锁允许多个线程通过确保对资源的互斥访问来安全地共享关联的硬件或软件资源。
概念
可以定义任意数量的互斥锁(仅受可用 RAM 的限制)。每个互斥锁都由其内存地址引用。
互斥锁具有以下关键属性:
- 一个锁定计数,指示互斥锁的线程锁定互斥锁的次数。计数为零表示互斥锁已解锁。
- 一个所属线程,用于标识已锁定互斥锁的线程(当互斥锁被锁定时)。
必须先初始化互斥锁,然后才能使用它。这会将其锁定计数设置为零。
需要使用共享资源的线程必须首先通过锁定关联的互斥锁来获得访问该资源的独占权限。如果互斥锁已被另一个线程锁定,则请求线程可以选择等待互斥锁解锁。
锁定互斥锁后,线程可以根据需要安全地使用关联的资源;但是,最好将锁保持尽可能短的时间,以避免对要使用该资源的其他线程产生负面影响。当线程不再需要资源时,它必须解锁互斥锁以允许其他线程使用该资源。
任意数量的线程可以同时等待锁定的互斥锁。当互斥锁解锁时,它将被等待时间最长的最高优先级线程锁定。
重复锁定
允许线程锁定已锁定的互斥锁。这允许线程在执行访问共享资源时重复的锁定互斥锁。
在互斥锁完全解锁之前,必须解除由线程重复锁定的互斥锁相等的次数,以便另一个线程使用互斥锁。
优先级继承
已锁定互斥锁的线程有资格获得优先级继承
。这意味着,如果更高优先级的线程开始等待互斥锁,内核将暂时提升该线程的优先级。通过与等待线程相同的优先级执行来更快地释放互斥锁。解锁互斥锁后,解锁线程会将其优先级重置为之前的级别。
CONFIG_PRIORITY_CEILING配置选项限制了内核优先级继承时可以提高线程优先级的最大优先级。默认值 0 允许无限制的提升。
当两个或多个线程等待由较低优先级线程持有的互斥锁时,每次线程开始等待时,内核都会调整拥互斥锁线程的优先级。当互斥锁最终解锁时,解锁线程的优先级将正确恢复到其原始的非提升优先级。
当一个线程同时持有两个或多个互斥锁时,内核不完全支持优先级继承。这种情况可能导致线程的优先级在释放所有互斥锁后不会恢复到其原始的非提升优先级。建议线程在不同优先级的线程之间共享多个互斥体时仅锁定单个互斥锁。
定义互斥锁
互斥锁是使用k_mutex
类型的变量定义的。然后必须通过调用k_mutex_init()
对其进行初始化。
struct k_mutex my_mutex;
k_mutex_init(&my_mutex);
也可以通过调用K_MUTEX_DEFINE
在编译时定义和初始化互斥锁。
K_MUTEX_DEFINE(my_mutex);
锁定互斥锁
通过调用k_mutex_lock()
来锁定互斥锁。
如果互斥体已被另一个线程锁定,则无限期等待互斥锁变为可用。
k_mutex_lock(&my_mutex, K_FOREVER);
以下代码最多等待 100 毫秒,以便互斥锁变为可用,并在互斥锁不可用时发出警告。
if (k_mutex_lock(&my_mutex, K_MSEC(100)) == 0) {
/* mutex successfully locked */
} else {
printf("Cannot lock XYZ display\n");
}
解锁互斥锁
互斥锁通过调用k_mutex_unlock()
来解锁
k_mutex_unlock(&my_mutex);
互斥锁的Kconfig
Kconfig | 描述 |
---|---|
CONFIG_PRIORITY_CEILING | 优先继承上限 |