(二)任务间通信
1) 互斥量
互斥量又称互斥锁,一般用于共享资源的互斥排他性访问保护。
互斥量在任意时刻处于且仅会处于解锁或锁定状态,当一个任务获取到一把锁后(互斥量锁定),其他任务再尝试获得这把锁时会失败或进入阻塞状态,当该任务释放持有的锁时(互斥量解锁),会唤醒一个正阻塞等待此互斥量的任务,被唤醒的任务将会获取这把锁。
在多任务运行环境中,有些共享资源不具有多线程可重入性,对于这类不希望被多任务同时访问的资源(临界资源),可以采用互斥量来进行保护,后面的编程实例章节会演示这一编程范式。
互斥量mutex
tos_mutex_create
k_err_t tos_mutex_create(k_mutex_t *mutex);
• 功能描述
创建一个互斥量。
• 参数解释
IN/OUT 参数名 描述
[in] mutex 互斥量句柄
• 返回值
K_ERR_NONE 互斥量创建成功。
K_ERR_OBJ_PTR_NULL mutex为空指针。
tos_mutex_destroy
k_err_t tos_mutex_destroy(k_mutex_t *mutex);
• 功能描述
销毁一个互斥量。
• 参数解释
IN/OUT 参数名 描述
[in] mutex 互斥量句柄
• 返回值
K_ERR_NONE 互斥量销毁成功。
K_ERR_OBJ_PTR_NULL mutex为空指针。
K_ERR_OBJ_INVALID mutex指向的不是一个合法的互斥量。
tos_mutex_pend
k_err_t tos_mutex_pend(k_mutex_t *mutex);
• 功能描述
尝试获取一个互斥量(永久阻塞式等待)。
• 参数解释
IN/OUT 参数名 描述
[in] mutex 互斥量句柄
• 返回值
K_ERR_NONE 获取互斥量成功。
K_ERR_MUTEX_NESTING_OVERFLOW 互斥量拥有者嵌套获取溢出。
K_ERR_MUTEX_NESTING 互斥量拥有者嵌套获取。
K_ERR_PEND_SCHED_LOCKED 此互斥量被其他任务持有,且系统调度处于锁定状态。
K_ERR_PEND_DESTROY 当前任务试图获取的互斥量被销毁(tos_mutex_destroy)了。
tos_mutex_pend_timed
k_err_t tos_mutex_pend(k_mutex_t *mutex, k_tick_t timeout);
• 功能描述
尝试获取一个互斥量(有限时间内的阻塞等待)。
• 参数解释
IN/OUT 参数名 描述
[in] mutex 互斥量句柄
[in] timeout 等待超时参数
• 返回值
K_ERR_NONE 获取互斥量成功。
K_ERR_MUTEX_NESTING_OVERFLOW 互斥量拥有者嵌套获取溢出。
K_ERR_MUTEX_NESTING 互斥量拥有者嵌套获取。
K_ERR_PEND_NOWAIT 此互斥量被其他任务持有,同时timeout参数为TOS_TIME_NOWAIT(表示获取不到互斥量时立即返回)
K_ERR_PEND_SCHED_LOCKED 此互斥量被其他任务持有(获取失败),且系统调度处于锁定状态。
K_ERR_PEND_TIMEOUT 在timeout时间范围内未获取到互斥量。
K_ERR_PEND_DESTROY 当前任务试图获取的互斥量被销毁(tos_mutex_destroy)了。
tos_mutex_post
k_err_t tos_mutex_post(k_mutex_t *mutex);
• 功能描述
释放互斥量。
• 参数解释
IN/OUT 参数名 描述
[in] mutex 互斥量句柄
• 返回值
K_ERR_NONE 互斥量释放成功。
K_ERR_MUTEX_NOT_OWNER 当前任务并非此互斥量的拥有者。
K_ERR_MUTEX_NESTING_OVERFLOW 互斥量拥有者嵌套释放溢出。
K_ERR_MUTEX_NESTING 互斥量拥有者嵌套释放。
程序实例:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "string.h"
#include "cmsis_os.h"
#include "tos.h"
//定义相关堆栈大小
#define STK_SIZE_TASK_WRITER 512
#define STK_SIZE_TASK_READER 512
//定义任务堆栈
k_stack_t stack_task_writer[STK_SIZE_TASK_WRITER];
k_stack_t stack_task_reader[STK_SIZE_TASK_READER];
//任务体
k_task_t task_write;
k_task_t task_read;
//任务函数
void write_task(void *arg);
void read_task(void *arg);
//定义互斥任务锁
k_mutex_t critical_resource_locker;
static char resource[10];
static void write_sth(void)
{
u8 i=0;
printf("\r\nwrite something\r\n");
for(i=0;i<=9;i++)
{
printf("write: %d\r\n",i);
resource[i]=i;
}
}
static void read_sth(void)
{
u8 i=0;
printf("\r\nread something\r\n");
for(i=0;i<=9;i++)
{
printf("read: %d\r\n",resource[i]);
}
}
void write_task(void *arg)
{
k_err_t err;
while(1)
{
//尝试获取保护锁
err=tos_mutex_pend(&critical_resource_locker);
if (err == K_ERR_NONE)
{
// 成功获取锁之后,向临界区写入数据
write_sth();
// 写完数据后,释放互斥锁
tos_mutex_post(&critical_resource_locker);
}
else
{
printf("\r\nwrite:the target is being visited");
}
tos_task_delay(100);
}
}
void read_task(void *arg)
{
k_err_t err;
while(1)
{
// 读取临界区数据之前,先尝试获取临界区保护锁
err = tos_mutex_pend(&critical_resource_locker);
if (err == K_ERR_NONE) {
// 成功获取锁之后,从临界区读取数据
read_sth();
// 读取数据完毕后,释放互斥锁
tos_mutex_post(&critical_resource_locker);
}
else
{
printf("\r\nwrite:the target is being visited");
}
tos_task_delay(100);
}
}
int main(void)
{
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
LCD_Init();
tos_knl_init();
tos_mutex_create(&critical_resource_locker);
(void)tos_task_create(&task_write, //任务体指针
"write_task", //任务名
write_task, //任务函数入口
NULL , //入口参数
1, //任务优先级
stack_task_writer, //任务堆栈起始地址
STK_SIZE_TASK_WRITER, //堆栈大小
0 //时间片大小
);
(void)tos_task_create(&task_read, //任务体指针
"read_task", //任务名
read_task, //任务函数入口
NULL, //入口参数
2, //任务优先级
stack_task_reader, //任务堆栈起始地址
STK_SIZE_TASK_READER, //堆栈大小
0 //时间片大小
);
tos_knl_start();
while(1)
{}
}
实验现象:
两个函数一个写,一个读