目录
一 ucos-iii 信号量相关函数
创建信号量 | OSSemCreate() | OS_CFG_SEM_EN | OS_SEM SwSem; OS_ERR err; OSSemCreate(&SwSem, “Switch Semaphore”, |
删除信号量 | OSSemDel() | OS_CFG_SEM_EN OS_CFG_SEM_DEL_EN | OS_SEM SwSem; OS_ERR err; qty = OSSemDel(&SwSem,OS_OPT_DEL_ALWAYS, |
等待信号量 | OSSemPend() | OS_CFG_SEM_EN | OS_SEM SwSem; OS_ERR err; ctr = OSSemPend(&SwSem,0, |
取消等待 | OSSemPendAbort() | OS_CFG_SEM_EN OS_CFG_SEM_PEND_ABORT_EN | OS_SEM SwSem; OS_ERR err; nbr_tasks = OSSemPendAbort(&SwSem, |
释放信号量 | OSSemPost() | OS_CFG_SEM_EN | OS_SEM SwSem; OS_ERR err; ctr = OSSemPost(&SwSem, |
强制设置信号量的值 | OSSemSet() | OS_CFG_SEM_EN OS_CFG_SEM_SET_EN | OS_SEM SwSem; OS_ERR err; OSSemSet(&SwSem,0,&err); |
二 使用信号量
使用信号量访问共享资源:
如果一个资源被多个任务访问,则在访问前调用OSSemPend()请求资源,在访问结束后调用OSSemPost ()函数释放资源
OS_SEM MY_SEM; //定义一个信号量,用于访问共享资源
uint8_t share_res[30]; //共享资源区
//创建一个信号量
OSSemCreate ((OS_SEM* )&MY_SEM, //指向信号量
(CPU_CHAR* )"MY_SEM", //信号量名字
(OS_SEM_CTR )1, //信号量值为 1
(OS_ERR* )&err);
void sem0_task(void *p_arg)
{
OS_ERR err;
uint8_t task0_str[]="sem0 Running!";
p_arg = p_arg;
while(1)
{
printf("sem0_task:\r\n");
OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); // 请求信号量
memcpy(share_res,task0_str,sizeof(task0_str)); // 向共享资源区拷贝数据
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相对性延时1000个时钟节拍(1s)
OSSemPost (&MY_SEM,OS_OPT_POST_1,&err); // 释放信号量
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相对性延时1000个时钟节拍(1s)
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
uint8_t task1_str[]="sem1 Running!";
while(1)
{
printf("sem1_task:\r\n");
OSSemPend(&MY_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); // 请求信号量
memcpy(share_res,task1_str,sizeof(task1_str)); // 向共享资源区拷贝数据
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相对性延时1000个时钟节拍(1s)
OSSemPost (&MY_SEM,OS_OPT_POST_1,&err); // 释放信号量
OSTimeDly (100, OS_OPT_TIME_DLY, &err ); //相对性延时1000个时钟节拍(1s)
}
}
使用信号量访问共享资源会导致优先级翻转,所以一般不推荐使用,下面举例说明:
1. 假设有ABC三个任务,优先级A>B>C,任务AC访问共享资源“res”,任务B不访问共享资源。
2. 现在C正在使用共享资源res,在使用过程中进行了任务调度,由于A的优先级最高,所以接下来执行任务A
3. 由于A需要访问共享资源res,而res正在被C访问,所以任务A进入挂起状态,任务C继续执行。
4. 此时任务C仍在访问共享资源,任务A为挂起态,任务B为就绪态,所以当任务C进行了任务调度后,接下来执行任务B
在这种情况下,任务 A 的优先级实际上降到了任务 C 的优先级水平,任务 B 的优先级高于任务A。因为任务 A 要一直等待直到任务C释放其占用的那个共享资源。这就是优先级反转。
使用信号量实现任务同步:
任务一通过OSSemPost()发送信号量。
任务二通过OSSemPend()不断请求信号量,如果没有请求到信号量,则进行任务调度,执行下一个任务;如果请求到信号量,则继续运行该任务。
OS_SEM SYNC_SEM; //定义一个信号量,用于访问共享资源
//创建一个信号量
OSSemCreate ((OS_SEM* )&MY_SEM, //指向信号量
(CPU_CHAR* )"MY_SEM", //信号量名字
(OS_SEM_CTR )1, //信号量值为 1
(OS_ERR* )&err);
void sem0_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
OSSemPost(&SYNC_SEM,OS_OPT_POST_1,&err);//发送信号量
OSTimeDly (100, OS_OPT_TIME_DLY, &err );//延时
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
uint16_t num = 0;
p_arg = p_arg;
while(1)
{
OSSemPend(&SYNC_SEM,0,OS_OPT_PEND_BLOCKING,0,&err);// 请求信号量
num++;
printf("请求信号量次数: %d\r\n",num);
OSTimeDly (1000, OS_OPT_TIME_DLY, &err ); //延时
}
}
三 互斥量(互斥信号量)常用函数
创建互斥信号量 | OSMutexCreate() | OS_CFG_MUTEX_EN | OS_MUTEX DispMutex; OS_ERR err; OSMutexCreate(&DispMutex, “Display Mutex”,&err); |
删除互斥型信号量 | OSMutexDel() | OS_CFG_MUTEX_EN OS_CFG_MUTEX_DEL_EN | OS_MUTEX DispMutex; OS_ERR err; qty = OSMutexDel(&DispMutex, |
等待互斥型信号量 | OSMutexPend() | OS_CFG_MUTEX_EN | OS_MUTEX DispMutex; OS_ERR err; CPU_TS ts; OSMutexPend(&DispMutex,0, |
取消等待 | OSMutexPendAbort() | OS_CFG_MUTEX_EN OS_CFG_MUTEX_PEND_ABORT_EN | OS_MUTEX DispMutex; OS_ERR err; qty = OSMutexPendAbort(&DispMutex, |
释放互斥型信号量 | OSMutexPost() | OS_CFG_MUTEX_EN | OS_MUTEX DispMutex; OS_ERR err; OSMutexPost(&DispMutex, |
四 使用互斥信号量访问共享资源
OS_MUTEX TEST_MUTEX; //定义一个互斥信号量
uint8_t share_res[30]; //共享资源区
//创建一个互斥信号量
OSMutexCreate((OS_MUTEX* )&TEST_MUTEX,
(CPU_CHAR* )"TEST_MUTEX",
(OS_ERR* )&err);
void sem0_task(void *p_arg)
{
OS_ERR err;
uint8_t task0_str[]="sem0 Running!";
p_arg = p_arg;
while(1)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);// 请求互斥信号量
memcpy(share_res,task0_str,sizeof(task0_str));
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);// 释放互斥信号量
OSTimeDly (100, OS_OPT_TIME_DLY, &err );//延时
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
uint16_t num = 0;
uint8_t task1_str[]="sem1 Running!";
p_arg = p_arg;
while(1)
{
OSMutexPend (&TEST_MUTEX,0,OS_OPT_PEND_BLOCKING,0,&err);// 请求互斥信号量
memcpy(share_res,task1_str,sizeof(task1_str));
OSMutexPost(&TEST_MUTEX,OS_OPT_POST_NONE,&err);// 释放互斥信号量
OSTimeDly (100, OS_OPT_TIME_DLY, &err );//延时
}
}
五 任务内置信号量相关函数
等待任务信号量 | OSTaskSemPend() | OS_ERR err; ctr = OSTaskSemPend(100, | |
取消等待任务信号量 | OSTaskSemPendAbort() | OS_CFG_TASK_SEM_PEND_ABORT_EN | OS_TCB CommRxTaskTCB; OS_ERR err; aborted = OSTaskSemPendAbort(&CommRxTaskTCB, |
发送任务信号量 | OSTaskSemPost() | OS_TCB CommRxTaskTCB; OS_ERR err; OS_SEM_CTR ctr; ctr = OSTaskSemPost(&CommRxTaskTCB, | |
强行设置任务信号量计数 | OSTaskSemSet() | OS_TCB TaskY; OS_ERR err; ctr = OSTaskSemSet(&TaskY,0,&err); |
六 使用任务内置信号量
使用任务信号量不需要再定义与创建信号量,一般用作同步功能,如下列所示:
extern OS_TCB SEM1TaskTCB;
void sem0_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
OSTaskSemPost(&SEM1TaskTCB, OS_OPT_POST_NONE,&err); // 使用系统内建信号量向任务发送信号量
OSTimeDly (1000, OS_OPT_TIME_DLY, &err );//延时
}
}
void sem1_task(void *p_arg)
{
OS_ERR err;
p_arg = p_arg;
while(1)
{
OSTaskSemPend(0,OS_OPT_PEND_BLOCKING,0,&err); // 请求任务内建的信号量
printf("成功请求到内置信号量\r\n");
OSSched();
}
}