全部文档
OneOS简介 硬件支持 编译构造工具 API参考文档 高级语言 用户编程手册 应用笔记 FAQ

互斥锁


简介

互斥锁是一种任务间互斥的机制,一个任务占有了某个资源,就不允许别的任务去访问,直到占有资源的任务释放锁。即一个资源同时只允许一个访问者对其访问,具有唯一性和排他性,但互斥不会限制访问者对资源的访问顺序,即访问是无序的。

本操作系统的互斥锁支持非递归锁和递归锁两种形式。当互斥锁设置为非递归锁时,一旦该锁被某个任务获取,在释放之前不能被任何任务再次获取;当互斥锁设置为递归锁时,若锁被某个任务获取,那么该任务可以再次获取这个锁而不会被挂起。一般情况下,使用者在使用锁时,应该明确自己要保护的临界资源的范围,只在对临界资源访问时加锁,访问完成后立即解锁。对临界资源的访问,经过合理设计后,一般都可以使用非递归锁实现;递归锁在某些错综复杂的调用关系情况下,使用起来比较方便,但是容易隐藏代码中可能存在的问题。

在处理互斥场景时,如果使用信号量,可能会存在任务优先级反转问题,即当一个高优先级任务尝试通过信号量机制访问临界资源时,如果该信号量已被低优先级任务持有,而此低优先级任务运行过程中可能被其它中优先级任务抢占,可能导致高优先级任务长时间被阻塞,实时性难以保证。而互斥锁考虑到这种场景,会动态提升持有锁的任务的优先级,使其不被中优先级任务抢占,尽快完成对临界资源的访问然后释放锁,解决了优先级反转的问题。


重要定义及数据结构

结构体

struct os_mutex
{
    os_ipc_object_t parent;                        /* Inherit from os_ipc_object. */

    os_uint8_t      original_priority;             /* Priority of last task lock the mutex. */
    os_uint8_t      nested;                        /* Number of times current owner lock the mutex. */
    os_bool_t       recursive;                     /* Support recursive call. */

    os_task_t       *owner;                        /* Current owner of the mutex. */
};
struct os_mutex重要参数 说明
original_priority 持有该锁的任务的原始优先级
nested 持有该锁的任务的持有次数
recursive 该锁是否支持递归调用,若为TRUE,则持有该锁的任务可以再次获取该锁
owner 锁的当前持有者

API列表

接口 说明
os_mutex_init 以静态方式初始化互斥锁,即互斥锁对象由使用者提供;recursive为OS_FALSE时,为非递归锁;recursive为OS_TRUE时,为递归锁。对于非递归锁,只能被获取一次,只有该锁被释放后才能再次被获取;而对于递归锁,若某个任务已经获得锁,在释放该锁之前,该任务仍然可以多次获得该锁
os_mutex_deinit 反初始化互斥锁,与os_mutex_init()配对使用
os_mutex_create 以动态方式创建互斥锁并初始化,即互斥锁对象的空间采用动态申请内存的方式获取;recursive为OS_FALSE时,为非递归锁;recursive为OS_TRUE时,为递归锁。对于非递归锁,只能被获取一次,只有该锁被释放后才能再次被获取;而对于递归锁,若某个任务已经获得锁,在释放该锁之前,该任务仍然可以多次获得该锁
os_mutex_destroy 销毁互斥锁,与os_sem_create()匹配使用
os_mutex_lock 获取(非递归)锁
os_mutex_unlock 释放(非递归)锁
os_mutex_recursive_lock 获取(递归)锁
os_mutex_recursive_unlock 释放(递归)锁
os_mutex_control 控制或更改互斥锁的行为属性

os_mutex_init

该函数以静态方式初始化互斥锁,即互斥锁对象所使用的空间由使用者提供,函数原型如下:

os_err_t os_mutex_init(os_mutex_t *mutex, const char *name, os_ipc_flag_t flag, os_bool_t recursive);
参数 说明
mutex 互斥锁句柄
name 互斥锁名字
flag 标志,可以取OS_IPC_FLAG_FIFO和OS_IPC_FLAG_PRIO;当取值为OS_IPC_FLAG_FIFO时,等待的任务将按照先进先出的方式排队,先进入的任务先获得互斥锁;当取值为OS_IPC_FLAG_PRIO时,等待的任务将按照任务优先级排队,优先级高的任务先获得互斥锁
recursive 表明是否为递归锁。若为OS_FALSE,为非递归锁,只能被获取一次,只有该锁被释放后才能再次被获取;若为OS_TRUE时,为递归锁,即某个任务已经获得锁,在释放该锁之前,该任务仍然可以多次获得该锁
返回 说明
OS_EOK 初始化成功

os_mutex_deinit

该函数反初始化互斥锁,与os_mutex_init()配合使用,函数原型如下:

os_err_t os_mutex_deinit(os_mutex_t *mutex);
参数 说明
mutex 互斥锁句柄
返回 说明
OS_EOK 成功

os_mutex_create

该函数以动态方式创建并初始化互斥锁,即互斥锁对象使用的内存空间通过动态申请获得,函数原型如下:

os_mutex_t *os_mutex_create(const char *name, os_ipc_flag_t flag, os_bool_t recursive);
参数 说明
name 互斥锁名字
flag 标志,可以取OS_IPC_FLAG_FIFO和OS_IPC_FLAG_PRIO;当取值为OS_IPC_FLAG_FIFO时,等待的任务将按照先进先出的方式排队,先进入的任务先获得互斥锁;当取值为OS_IPC_FLAG_PRIO时,等待的任务将按照任务优先级排队,优先级高的任务先获得互斥锁
recursive 表明是否为递归锁。若为OS_FALSE,为非递归锁,只能被获取一次,只有该锁被释放后才能再次被获取;若为OS_TRUE时,为递归锁,即某个任务已经获得锁,在释放该锁之前,该任务仍然可以多次获得该锁
返回 说明
非OS_NULL 创建成功,返回互斥锁句柄
OS_NULL 创建失败

os_mutex_destroy

该函数销毁互斥锁,并释放互斥锁对象所占用的内存空间,与os_mutex_create()配合使用,原型如下:

os_err_t os_mutex_destroy(os_mutex_t *mutex);
参数 说明
mutex 互斥锁句柄
返回 说明
OS_EOK 成功

os_mutex_lock

该函数用于获取(非递归)互斥锁,若暂时获取不到锁且设定了超时时间,则当前任务会阻塞,函数原型如下:

os_err_t os_mutex_lock(os_mutex_t *mutex, os_tick_t timeout);
参数 说明
mutex 互斥锁句柄,该锁未被释放前,不能再次被获取
timeout 互斥锁暂时获取不到时的等待超时时间。若为OS_IPC_WAITING_NO,则直接返回OS_EBUSY;若为OS_IPC_WAITING_FOREVER,则永久等待直到获取到互斥锁;若为其它值,则等待timeout时间或者获取到互斥锁为止
返回 说明
OS_EOK 获取互斥锁成功
OS_EBUSY 不等待且未获取到互斥锁
OS_ETIMEOUT 等待超时未获取到互斥锁
OS_ERROR 其它错误

os_mutex_unlock

该函数用于释放(非递归)互斥锁,与os_mutex_lock()配合使用,函数原型如下:

os_err_t os_mutex_unlock(os_mutex_t *mutex);
参数 说明
mutex 互斥锁句柄
返回 说明
OS_EOK 释放成功

os_mutex_recursive_lock

该函数用于获取(递归)互斥锁,函数原型如下:

os_err_t os_mutex_recursive_lock(os_mutex_t *mutex, os_tick_t timeout);
参数 说明
mutex 互斥锁句柄,该锁未被释放前,可以被已经持有该锁的任务再次获取
timeout 互斥锁暂时获取不到时的等待超时时间。若为OS_IPC_WAITING_NO,则直接返回OS_EBUSY;若为OS_IPC_WAITING_FOREVER,则永久等待直到获取到互斥锁;若为其它值,则等待timeout时间或者获取到互斥锁为止
返回 说明
OS_EOK 获取互斥锁成功
OS_EBUSY 不等待且未获取到互斥锁
OS_ETIMEOUT 等待超时未获取到互斥锁
OS_ERROR 其它错误

os_mutex_recursive_unlock

该函数用于释放(递归)互斥锁,与os_mutex_recursive_lock()配套使用,函数原型如下:

os_err_t os_mutex_recursive_unlock(os_mutex_t *mutex);
参数 说明
mutex 互斥锁句柄
返回 说明
OS_EOK 释放成功
OS_ERROR 释放错误

os_mutex_control

该函数用于控制和改变互斥锁的属性,目前暂无支持的命令,函数原型如下:

os_err_t os_mutex_control(os_mutex_t *mutex, os_ipc_cmd_t cmd, void *arg);
参数 说明
mutex 互斥锁句柄
cmd 命令,目前暂无支持的命令
arg 不同命令时参数含义不同
返回 说明
OS_ERROR 错误

使用示例

静态互斥锁使用示例

本例采用静态方式初始化了一个(非递归)互斥锁,并在两个任务里面都去访问两个全局变量,使用互斥锁对这两个全局变量进行保护

#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <os_mutex.h>

#define TEST_TAG        "TEST"
#define TASK_STACK_SIZE 1024
#define TASK1_PRIORITY  15
#define TASK2_PRIORITY  16
#define TASK_TIMESLICE  10

static os_uint32_t count1 = 0;
static os_uint32_t count2 = 0;
static os_mutex_t mutex_static;

void task1_entry(void *para)
{
    while (1)
    {        
        if (OS_EOK == os_mutex_lock(&mutex_static, OS_IPC_WAITING_FOREVER))
        {
            LOG_W(TEST_TAG, "task1 mutex lock");
        }
        else
        {
            LOG_W(TEST_TAG, "task1 mutex lock err");
        }

        count1++;
        LOG_W(TEST_TAG, "task1 sleep");
        os_task_sleep(100);
        count2++;
        if (OS_EOK == os_mutex_unlock(&mutex_static))
        {
            LOG_W(TEST_TAG, "task1 mutex unlock");
        }
        else
        {
            LOG_W(TEST_TAG, "task1 mutex unlock err");
        }
        os_task_sleep(500);
    }
}

void task2_entry(void *para)
{
    while (1)
    {
        if (OS_EOK == os_mutex_lock(&mutex_static, OS_IPC_WAITING_FOREVER))
        {
            LOG_W(TEST_TAG, "task2 mutex lock");
        }
        else
        {
            LOG_W(TEST_TAG, "task2 mutex lock err");
        }

        LOG_W(TEST_TAG, "task2 count1:%d count2:%d", count1, count2);
        count1++;
        count2++;
        if (OS_EOK == os_mutex_unlock(&mutex_static))
        {
            LOG_W(TEST_TAG, "task2 mutex unlock");
        }
        else
        {
            LOG_W(TEST_TAG, "task2 mutex unlock err");
        }

        os_task_sleep(500);
    }
}

void mutex_static_sample(void)
{
    os_task_t *task1 = OS_NULL;
    os_task_t *task2 = OS_NULL;

    os_mutex_init(&mutex_static, "mutex_static", OS_IPC_FLAG_FIFO, OS_FALSE);

    task1 = os_task_create("task1", 
                           task1_entry, 
                           OS_NULL, 
                           TASK_STACK_SIZE, 
                           TASK1_PRIORITY, 
                           TASK_TIMESLICE);
    if (task1)
    {
        os_task_startup(task1);
    }

    task2 = os_task_create("task2", 
                           task2_entry, 
                           OS_NULL, 
                           TASK_STACK_SIZE, 
                           TASK2_PRIORITY, 
                           TASK_TIMESLICE);
    if (task2)
    {
        os_task_startup(task2);
    }
}

SH_CMD_EXPORT(static_mutex, mutex_static_sample, "test staitc mutex");

运行结果如下:

sh />static_mutex
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex unlock
W/TEST: task2 mutex lock
W/TEST: task2 count1:1 count2:1
W/TEST: task2 mutex unlock
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex unlock
W/TEST: task2 mutex lock
W/TEST: task2 count1:3 count2:3
W/TEST: task2 mutex unlock
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex unlock
W/TEST: task2 mutex lock
W/TEST: task2 count1:5 count2:5
W/TEST: task2 mutex unlock
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex unlock
W/TEST: task2 mutex lock
W/TEST: task2 count1:7 count2:7
W/TEST: task2 mutex unlock

动态互斥锁使用示例

本例采用动态方式创建并初始化了(递归)互斥锁,并在两个任务里面都去访问两个全局变量,使用互斥锁对这两个全局变量进行保护。本例中的递归互斥锁的使用没有实际意义,仅为演示递归锁的使用方法及效果

#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <os_mutex.h>

#define TEST_TAG        "TEST"
#define TASK_STACK_SIZE 1024
#define TASK1_PRIORITY  15
#define TASK2_PRIORITY  16
#define TASK_TIMESLICE  10

#define TEST_RECURSIVE_CNT 3

static os_uint32_t count1 = 0;
static os_uint32_t count2 = 0;
static os_mutex_t *mutex_dynamic = OS_NULL;

void task1_entry(void *para)
{
    os_uint32_t i = 0;

    while (1)
    {   
        for (i = 0; i < TEST_RECURSIVE_CNT; i++)
        {
            if (OS_EOK == os_mutex_recursive_lock(mutex_dynamic, OS_IPC_WAITING_FOREVER))
            {
                LOG_W(TEST_TAG, "task1 mutex lock");    
                count1++;
                LOG_W(TEST_TAG, "task1 sleep");
                os_task_sleep(100);
                count2++;
            }
            else
            {
                LOG_W(TEST_TAG, "task1 mutex lock err");
            }
        }

        for (i = 0; i < TEST_RECURSIVE_CNT; i++)
        {
            if (OS_EOK == os_mutex_recursive_unlock(mutex_dynamic))
            {
                LOG_W(TEST_TAG, "task1 mutex unlock");
            }
            else
            {
                LOG_W(TEST_TAG, "task1 mutex unlock err");
            }
        }
        os_task_sleep(500);
    }
}

void task2_entry(void *para)
{
    while (1)
    {
        if (OS_EOK == os_mutex_recursive_lock(mutex_dynamic, OS_IPC_WAITING_FOREVER))
        {
            LOG_W(TEST_TAG, "task2 mutex lock");
        }
        else
        {
            LOG_W(TEST_TAG, "task2 mutex lock err");
        }

        LOG_W(TEST_TAG, "task2 count1:%d count2:%d", count1, count2);
        count1++;
        count2++;
        if (OS_EOK == os_mutex_recursive_unlock(mutex_dynamic))
        {
            LOG_W(TEST_TAG, "task2 mutex unlock");
        }
        else
        {
            LOG_W(TEST_TAG, "task2 mutex unlock err");
        }

        os_task_sleep(500);
    }
}

void mutex_dynamic_sample(void)
{
    os_task_t *task1 = OS_NULL;
    os_task_t *task2 = OS_NULL;

    mutex_dynamic = os_mutex_create("mutex_dynamic", OS_IPC_FLAG_FIFO, OS_TRUE);

    task1 = os_task_create("task1", 
                           task1_entry, 
                           OS_NULL, 
                           TASK_STACK_SIZE, 
                           TASK1_PRIORITY, 
                           TASK_TIMESLICE);
    if (task1)
    {
        os_task_startup(task1);
    }

    task2 = os_task_create("task2", 
                           task2_entry, 
                           OS_NULL, 
                           TASK_STACK_SIZE, 
                           TASK2_PRIORITY, 
                           TASK_TIMESLICE);
    if (task2)
    {
        os_task_startup(task2);
    }
}

SH_CMD_EXPORT(dynamic_mutex, mutex_dynamic_sample, "test dynamic mutex");

运行结果如下,可以看到task1获得递归互斥锁之后,仍然可以再次获得递归互斥锁,而task2必须等task1把递归互斥锁完全释放完之后才能获取到锁:

sh />dynamic_mutex
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex unlock
W/TEST: task1 mutex unlock
W/TEST: task1 mutex unlock
W/TEST: task2 mutex lock
W/TEST: task2 count1:3 count2:3
W/TEST: task2 mutex unlock
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex unlock
W/TEST: task1 mutex unlock
W/TEST: task1 mutex unlock
W/TEST: task2 mutex lock
W/TEST: task2 count1:7 count2:7
W/TEST: task2 mutex unlock
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex lock
W/TEST: task1 sleep
W/TEST: task1 mutex unlock
W/TEST: task1 mutex unlock
W/TEST: task1 mutex unlock
[W/TEST: task2 mutex lock
[W/TEST: task2 count1:11 count2:11
W/TEST: task2 mutex unlock

results matching ""

    No results matching ""

    返回顶部