Q群:
电话:
邮箱:
地址:
信号量是一种解决同步问题的机制,可以实现对资源的有序访问,即一个任务完成了某个动作后,别的任务接下来才可以做其它事情。信号量的申请者和释放者可以不是同一个任务。
当信号量的取值只有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 | 信号量的值 |
接口 | 说明 |
---|---|
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_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_init()
匹配使用,其函数原型如下:
os_err_t os_sem_deinit(os_sem_t *sem);
参数 | 说明 |
---|---|
sem | 信号量句柄 |
返回 | 说明 |
OS_EOK | 反初始化成功 |
该函数用于创建信号量并初始化,信号量对象使用的内存采用动态申请的方式获取,其函数原型如下:
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_create()
匹配使用,其函数原型如下:
os_err_t os_sem_destroy(os_sem_t *sem);
参数 | 说明 |
---|---|
sem | 信号量句柄 |
返回 | 说明 |
OS_EOK | 销毁成功 |
该函数用于获取信号量,当信号量的值大于等于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 | 其它错误 |
该函数用于释放信号量,如果有任务等待在该信号量则唤醒等待列表的第一个任务,否则信号量计数值加1,其函数原型如下:
os_err_t os_sem_post(os_sem_t *sem);
参数 | 说明 |
---|---|
sem | 信号量句柄 |
返回 | 说明 |
OS_EOK | 释放信号量成功 |
该函数用于控制或改变信号量的属性,其函数原型如下:
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