NCS-OS系列13 :互斥锁
前言
ncs 相关文章,部分为原始文档翻译,水平有限,如果有错误,欢迎指出。
本文参考链接:
https://docs.zephyrproject.org/latest/reference/kernel/synchronization/mutexes.html
概念
互斥锁是一个内核对象,它实现了一个通用的可重入互斥锁。互斥锁通过确保对资源的互斥访问,允许多个线程安全地共享相关的硬件或软件资源。
可以定义任意数量的互斥对象(仅受可用RAM的限制),每个互斥量都由它的内存地址来引用。
互斥量有如下关键属性:
- 锁计数(
lock count
),表示锁住互斥锁的线程锁住互斥锁的次数。计数为0表示互斥锁已解锁。 - 当互斥锁被锁定时,拥有该互斥锁的线程(
owning thread
)
互斥量在使用前必须进行初始化,初始化后lock count
被初始化为0。
需要使用共享资源的线程必须首先通过锁定相关的互斥锁获得访问该资源的独占权限,如果互斥锁已经被另一个线程锁定,请求线程可以选择等待互斥锁被解锁。
在锁定了互斥锁之后,线程可以根据需要安全地使用相关的资源;但是,持有锁的时间越短越好,以避免对其他想要使用资源的线程产生负面影响。当线程不再需要资源时,它必须解锁互斥锁以允许其他线程使用资源。
任意数量的线程都可以同时等待一个锁定的互斥锁。当互斥锁被解锁时,它就会被等待时间最长的最高优先级的线程锁定。
可重入锁
允许线程锁定已经锁定的互斥对象。这允许线程在其执行时访问相关的资源,而互斥锁可能已经锁定,也可能还没有锁定。
被一个线程反复锁定的互斥锁在完全解锁之前,必须解锁相同次数的互斥锁,以便另一个线程可以获取它。
优先级继承
锁定了互斥锁的线程可以进行优先级继承。这意味着如果更高优先级的线程开始等待互斥锁,内核将临时提高拥有互斥锁的线程的优先级,这允许拥有互斥锁的线程以与等待线程相同的优先级执行,从而更快地完成工作并释放互斥锁。一旦互斥锁被解除锁定,解除锁定的线程就会将其优先级重置为锁定互斥锁之前的级别。
注意,由于优先级继承,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()
进行锁定。
下面代码进行互斥锁的锁定,如果互斥锁已经被锁定,那么无限期的等待互斥锁的解锁:
struct k_mutex my_mutex;
k_mutex_init(&my_mutex);
k_mutex_lock(&my_mutex, K_FOREVER);
下面代码等待互斥锁解锁100ms,否则上报一个错误报告:
struct k_mutex my_mutex;
k_mutex_init(&my_mutex);
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