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

信号量


简介

信号量是一种解决同步问题的机制,可以实现对资源的有序访问,即一个任务完成了某个动作后,别的任务接下来才可以做其它事情。信号量的申请者和释放者可以不是同一个任务。

当信号量的取值只有0和1(即为二值信号量)时,如果参考互斥锁的使用方式,也可以用于对资源的互斥访问,不过采用这种用法时不能解决可能存在的优先级反转问题。


重要定义及数据结构

结构体

struct os_semaphore
{
    os_ipc_object_t parent;                        /* Inherit from os_ipc_object. */
    os_uint16_t     count;                         /* Count of semaphore. */
};
struct os_semaphore重要参数 说明
count 信号量的值

API列表

接口 说明
os_sem_init 以静态方式初始化信号量,信号量对象的内存空间由使用者提供
os_sem_deinit 反初始化信号量,与os_sem_init()匹配使用
os_sem_create 以动态方式创建信号量并初始化,信号量对象的内存空间采用动态申请的方式获取
os_sem_destroy 销毁信号量,与os_sem_create()匹配使用
os_sem_wait 获取信号量
os_sem_post 释放信号量
os_sem_control 控制或改变信号量的行为属性

os_sem_init

该函数用于以静态方式初始化信号量,信号量对象所使用的内存空间是由使用者提供的,其函数原型如下:

os_err_t os_sem_init(os_sem_t *sem, const char *name, os_uint16_t value, os_ipc_flag_t flag);
参数 说明
sem 信号量句柄(信号量对象的指针)
name 信号量名字
value 信号量的初始值
flag 标志,可以取OS_IPC_FLAG_FIFO和OS_IPC_FLAG_PRIO;当取值为OS_IPC_FLAG_FIFO时,等待的任务将按照先进先出的方式排队,先进入的任务先获得信号量;当取值为OS_IPC_FLAG_PRIO时,等待的任务将按照任务优先级排队,优先级高的任务先获得信号量
返回 说明
OS_EOK 初始化成功

os_sem_deinit

该函数用于反初始化信号量,将唤醒所有等待任务,并从内核对象容器中移除该信号量对象,与os_sem_init()匹配使用,其函数原型如下:

os_err_t os_sem_deinit(os_sem_t *sem);
参数 说明
sem 信号量句柄
返回 说明
OS_EOK 反初始化成功

os_sem_create

该函数用于创建信号量并初始化,信号量对象使用的内存采用动态申请的方式获取,其函数原型如下:

os_sem_t *os_sem_create(const char *name, os_uint16_t value, os_ipc_flag_t flag);
参数 说明
name 信号量名字
value 信号量的初始值
flag 标志,可以取OS_IPC_FLAG_FIFO和OS_IPC_FLAG_PRIO;当取值为OS_IPC_FLAG_FIFO时,等待的任务将按照先进先出的方式排队,先进入的任务先获得信号量;当取值为OS_IPC_FLAG_PRIO时,等待的任务将按照任务优先级排队,优先级高的任务先获得信号量
返回 说明
非OS_NULL 创建成功,返回信号量句柄
OS_NULL 创建失败

os_sem_destroy

该函数用于销毁创建的信号量,将唤醒所有等待任务,并从内核对象容器中移除该信号量对象,然后释放信号量对象占用的空间,与os_sem_create()匹配使用,其函数原型如下:

os_err_t os_sem_destroy(os_sem_t *sem);
参数 说明
sem 信号量句柄
返回 说明
OS_EOK 销毁成功

os_sem_wait

该函数用于获取信号量,当信号量的值大于等于1时,该任务将获得信号量;若信号量的值为0,则申请该信号量的任务将会根据timeout的设置来决定等待的时间,直到其它任务/中断释放该信号量,或者超时(注意该接口可能会导致上下文挂起,不能在中断服务程序中使用)。其函数原型如下:

os_err_t os_sem_wait(os_sem_t *sem, os_tick_t timeout);
参数 说明
sem 信号量句柄
timeout 表示在当前信号量值为零时的等待时间。若timeout为OS_IPC_WAITING_FOREVER,则会永久等待,直到获取到信号量;若timeout为OS_IPC_WAITING_NO,则不等待直接返回,此时返回值为OS_EBUSY;若timeout为其它值,会等待设定的timeout时间或者获取到信号量为止
返回 说明
OS_EOK 获取信号量成功
OS_EBUSY 不等待且未获取到信号量
OS_ETIMEOUT 等待超时未获取到信号量
OS_ERROR 其它错误

os_sem_post

该函数用于释放信号量,如果有任务等待在该信号量则唤醒等待列表的第一个任务,否则信号量计数值加1,其函数原型如下:

os_err_t os_sem_post(os_sem_t *sem);
参数 说明
sem 信号量句柄
返回 说明
OS_EOK 释放信号量成功

os_sem_control

该函数用于控制或改变信号量的属性,其函数原型如下:

os_err_t os_sem_control(os_sem_t *sem, os_ipc_cmd_t cmd, void *arg);
参数 说明
cmd 控制命令,目前支持OS_IPC_CMD_RESET
arg 当cmd为OS_IPC_CMD_RESET时,表示新设置的信号量的值
返回 说明
OS_EOK 控制或改变成功
OS_ERROR 错误

使用示例

静态信号量使用示例

本例以静态方式初始化了信号量,并且创建了两个任务,在一个任务中申请信号量,在另外一个任务中释放信号量,只有当信号量被释放后,申请信号量的任务才能拿到信号量并往下执行

#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <os_sem.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 count = 0;
static os_sem_t sem_static;

void task1_entry(void *para)
{
    while (1)
    {        
        LOG_W(TEST_TAG, "task1_entry semaphore wait");
        if (OS_EOK == os_sem_wait(&sem_static, OS_IPC_WAITING_FOREVER))
        {
            LOG_W(TEST_TAG, "task1_entry semaphore wait done, count:%d", count);
        }
        else
        {
            LOG_W(TEST_TAG, "task1_entry semaphore wait fail");
        }
    }
}

void task2_entry(void *para)
{
    while (1)
    {
        count++;
        LOG_W(TEST_TAG, "task2_entry semaphore post");
        if (OS_EOK != os_sem_post(&sem_static))
        {
            LOG_W(TEST_TAG, "task2_entry semaphore post fail");
        }

        LOG_W(TEST_TAG, "task2_entry sleep");
        os_task_sleep(500);
    }
}

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

    os_sem_init(&sem_static, "sem_static", 0, OS_IPC_FLAG_FIFO);

    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_sem, semaphore_static_sample, "test staitc semaphore");

运行结果如下:

sh />static_sem
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:1
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:2
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:3
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:4
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:5
W/TEST: task1_entry semaphore wait

动态信号量使用示例

本例与静态信号量使用示例类似,只是信号量是以动态方式创建的

#include <oneos_config.h>
#include <os_dbg.h>
#include <os_errno.h>
#include <os_task.h>
#include <shell.h>
#include <os_sem.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 count = 0;
static os_sem_t* sem_dynamic;

void task1_entry(void *para)
{
    while (1)
    {        
        LOG_W(TEST_TAG, "task1_entry semaphore wait");
        if (OS_EOK == os_sem_wait(sem_dynamic, OS_IPC_WAITING_FOREVER))
        {
            LOG_W(TEST_TAG, "task1_entry semaphore wait done, count:%d", count);
        }
        else
        {
            LOG_W(TEST_TAG, "task1_entry semaphore wait fail");
        }
    }
}

void task2_entry(void *para)
{
    while (1)
    {
        count++;
        LOG_W(TEST_TAG, "task2_entry semaphore post");
        if (OS_EOK != os_sem_post(sem_dynamic))
        {
            LOG_W(TEST_TAG, "task2_entry semaphore post fail");
        }

        LOG_W(TEST_TAG, "task2_entry sleep");
        os_task_sleep(500);
    }
}

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

    sem_dynamic = os_sem_create("sem_dynamic", 0, OS_IPC_FLAG_FIFO);

    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_sem, semaphore_dynamic_sample, "test dynamic semaphore");

运行结果如下:

sh />dynamic_sem
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:1
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:2
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:3
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:4
W/TEST: task1_entry semaphore wait
W/TEST: task2_entry sleep
W/TEST: task2_entry semaphore post
W/TEST: task1_entry semaphore wait done, count:5
W/TEST: task1_entry semaphore wait

results matching ""

    No results matching ""

    返回顶部