#include
#define TEST_SEM_EN 0 //test switch, 0: off 1:on
#define TASK_STK_SIZE 128
OS_STK Task01Stk[TASK_STK_SIZE];
OS_STK Task02Stk[TASK_STK_SIZE];
static OS_EVENT *sem_p;
static OS_EVENT *sem_v;
static void task_01(void *p_arg);
static void task_02(void *p_arg);
void main(int argc, char *argv[])
{
OSInit();
//create P V semaphore
sem_p = OSSemCreate(1);
sem_v = OSSemCreate(1);
OSTaskCreate(task_01, NULL, (OS_STK *)&Task01Stk[TASK_STK_SIZE-1], (INT8U)10);
OSTaskCreate(task_02, NULL, (OS_STK *)&Task02Stk[TASK_STK_SIZE-1], (INT8U)11);
OSStart();
}
void task_01(void *p_arg)
{
INT8U err;
p_arg = p_arg;
while (TRUE)
{
#if TEST_SEM_EN
OSSemPend(sem_p, 0, &err);
#endif
OS_Printf("A");
OSTimeDlyHMSM(0, 0, 1, 0);
#if TEST_SEM_EN
OSSemPost(sem_v);
#endif
}
}
void task_02(void *p_arg)
{
INT8U err;
p_arg = p_arg;
while (TRUE)
{
#if TEST_SEM_EN
OSSemPend(sem_v, 0, &err);
#endif
OS_Printf("B");
OSTimeDlyHMSM(0, 0, 3, 0);
#if TEST_SEM_EN
OSSemPost(sem_p);
#endif
}
}
不使用信号量运行的结果(将宏TEST_SEM_EN设置为 0)
进程同步,使用信号量控制,运行结果(将宏TEST_SEM_EN设置为1)
信号量(Semaphores)
信 号量对象对线程的同步方式与前面几种方法不同,信号允许多个线程同时使用共享资源,这与操作系统中的PV操作相同。它指出了同时访问共享资源的线程最大数 目。它允许多个线程在同一时刻访问同一资源,但是需要限制在同一时刻访问此资源的最大线程数目。在用CreateSemaphore()创建信号量时即要 同时指出允许的最大资源计数和当前可用资源计数。一般是将当前可用资源计数设置为最大资源计数,每增加一个线程对共享资源的访问,当前可用资源计数就会减 1,只要当前可用资源计数是大于0的,就可以发出信号量信号。但是当前可用计数减小到0时则说明当前占用资源的线程数已经达到了所允许的最大数目,不能在 允许其他线程的进入,此时的信号量信号将无法发出。线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源 计数加1。在任何时候当前可用资源计数决不可能大于最大资源计数。
PV操作及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量S是一个整数,S大于等于零时代表可供并发进程使用的资源实体数,但S小于零时则表示正在等待使用共享资源的进程数。
P操作 申请资源:
(1)S减1;
(2)若S减1后仍大于等于零,则进程继续执行;
(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转入进程调度。
V操作 释放资源:
(1)S加1;
(2)若相加结果大于零,则进程继续执行;
(3)若相加结果小于等于零,则从该信号的等待队列中唤醒一个等待进程,然后再返回原进程继续执行或转入进程调度。
对于信号量,uCOS II中共提供了六个函数:OSSemCreate 、OSSemDel、OSSemPend、OSSemPost、OSSemAccept、OSSemQuery。
其中我们常用的只有三个即 OSSemCreate 、OSSemPend、OSSemPost 。
信号量的结构为:
typedef struct {
INT8U OSEventType;
INT8U OSEventGrp;
INT16U OSEventCnt;
void *OSEventPtr;
INT8U OSEventTbl[OS_EVENT_TBL_SIZE];
} OS_EVENT;
OSSemCreate的函数原型为:OS_EVENT *OSSemCreate(INT16U cnt),cnt 表示在实际使用中有多少个相同的资源,cnt的值就是OSEventCnt的值。
OSSemPend的函数原型为:void OSSemPend(OS_EVENT *pevent,INT16U timeout,INT8U err),pevent:就是要请求的信号量地址;timeout:请求的超时时间,如果为0表示无限时等待;err:用来返回是否出错。每执行一次 OSSemPend,OSEventCnt就会减1。如果OSEventCnt值为0,执行OSSemPend时,当时任务将因为无法得到相应的资源而被 挂起。
OSSemPost的函数原型为:INT8U OSSemPost(OS_EVENT *pevent),同样pevent 就是要发送的信号量地址;每执行一次OSSemPost,OSEventCnt就会加1