本笔记基于 Zephyr 版本 2.6.0-rc2
本人正在学习 Zephyr,一个可移植性较强,可以兼容多种开发板及物联网设备的操作系统,如果你感兴趣,可以点此查看我的 学习笔记总述 进行了解!
互斥锁是一个实现了传统的可重入互斥锁的内核对象。互斥锁允许多个线程通过确保对资源的互斥访问来安全地共享相关的硬件或软件资源。
可以定义任意数量的互斥锁 (仅受可用 RAM 限制)。每个互斥锁由其内存地址引用。
互斥锁具有以下关键属性:
互斥锁在被使用之前必须被初始化。这将其锁计数设置为零。
需要使用共享资源的线程必须首先通过锁定关联的互斥锁获得访问该资源的独占权限。如果互斥锁已经被另一个线程锁定,发出请求的线程可以选择等待互斥锁被解锁。
锁定互斥锁后,线程可以根据需要安全地使用相关的资源;但是,保持锁的时间越短越好,这样可以避免对希望使用该资源的其他线程产生负面影响。当线程不再需要该资源时,它必须解锁互斥锁,以允许其他线程使用该资源。
任何数量的线程都可以同时等待一个锁定的互斥锁。当互斥锁被解锁后,它将被等待时间最长的最高优先级线程锁定。
互斥对象不是为 ISR 使用而设计的。
一个线程被允许锁定它已经锁定的互斥锁。这允许线程在互斥锁可能已经被锁定,也可能还没有被锁定时,在其执行的某个点访问相关的资源。
被一个线程反复锁定的互斥锁必须被解锁相同的次数,然后互斥锁才会被完全解锁,这样它才能被另一个线程使用。
锁定互斥锁的线程有资格获得优先级继承。这意味着如果一个更高优先级的线程开始等待互斥锁,内核将暂时提升锁定线程的优先级。这允许拥有互斥锁的线程完成它的工作,并通过执行与等待线程相同的优先级来更快地释放互斥锁。一旦互斥锁被解锁,解锁的线程将其优先级重置为锁定互斥锁之前的级别。
Note:
由于优先级继承,配置选项 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);
使用互斥提供对资源 (如物理设备) 的独占访问。
相关配置选项:
CONFIG_PRIORITY_CEILING
https://docs.zephyrproject.org/latest/reference/kernel/synchronization/mutexes.html#