任务的同步和通信:
1.同步和互斥概念
任务同步:任务之间的这种制约性的按照一定执行顺序执行的合作运行机制叫做任务间的同步;
任务互斥:对某个共享资源,如果一个任务在使用,则其他任务只能等待,等待该任务是否该共享资源,等待的任务之一才能占有资源。
2. 事件
事件:任务间的同步依赖于任务间的通信,使用信号量、邮箱(消息邮箱)和消息队列这些被当作事件的中间环节来实现任务之间的通信。
任务发送事件、请求时间以及其他对事件的操作定义为全局函数,以供应程序所有任务来调用。
a.信号量
信号量是一类事件,使用信号量的最初目的,是为了共享资源设立一个表示该共享资源被占用情况的标志。
b.消息邮箱
在任务和任务之间通过传递一个数据(我们称呼这个数据为消息)的方式来进行通信。在内存中创建一个存储空间作为该数据的缓冲区。如果把这个缓冲区叫做
消息缓冲区,那么在任务间传递数据(消息)的一个最简单的方法就是传递消息缓冲区的指针。传递消息缓冲区指针的数据结构就叫做消息邮箱。
c.消息队列
定义一个指针数组,让数组的每个元素都存放一个消息缓冲区指针,那么任务就可以通过传递这个指针数组指针的方法来传递多个消息了。这种可以传递多个
消息的数据结构叫做消息队列。
d.等待任务列表
在多任务系统中,当一个事件被占用时,其他请求该事件的任务被暂时得不到事件的服务时应用处于等待状态。作为功能比较完善的事件,应用对这些等待任务有一定的
管理功能。这个管理功能包含两个方面:一是要对等待事件的所有任务进行记录并排序;二是应用允许任务有一定的等待时限。
使用一个INT8U OSEventTbl[]作为记录等待事件任务的记录表,这个表叫做等待任务表。变量OSEventGrp表示OSEventTbl[]数组中的序号。
3.事件控制块
uc/os-II使用叫做事件控制块ECB的数据结构来描述诸如信号量,邮箱(消息邮箱)和消息队列这些事件。
事件控制块数据结构如下:
typedef struct {
INT8U OSEventType; //事件的类型
INT8U OSEventCnt; //信号量计数器
void *OSEventPtr; //消息或消息队列的指针
INT8U OSEventGrp; // 等待事件的任务组
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; //任务等待表
};
OSEventType可取的值:
OS_EVENT_TYPE_SEM: 表明事件是信号量;
OS_EVENT_TYPE_MUTEX:表明事件是互斥型信号量;
OS_EVENT_TYPE_MBOX:表明事件是消息邮箱;
OS_EVENT_TYPE_Q:表明事件是消息队列;
OS_EVENT_TYPE_UNUSED:空事件控制块
4. 操作事件控制块的函数:
1).事件控制块的初始化函数: void OS_EventWaitListInit(OS_EVENT *pevent); // 事件控制块的指针;
2). 使一个任务进入等待状态的函数: void OS_EventTaskWait(OS_EVENT *pevent);
把一个任务置于等待状态要调用该函数;
3).是一个正在等待任务进入就绪状态的函数:
INT8U OS_EventTaskRdy(OS_EVENT *pevent, void *msg, INT8U msk)
4). 使一个等待超时的任务进入就绪状态的函数:
void OS_EventTo(OS_EVENT *pevent);
如果一个正在等待的事件的任务已经超过了等待的时间,却因为没有获取事件等原因而未具备可以运行的条件,却又要使它进入就绪状态。
5. 空事件控制块链表
在OSInit()中按应用程序使用事件的总数OS_MAX_EVENTS,创建OS_MAX_EVENTS个空事件控制块并借用OSEventPtr作为链接指针,把这些空事件控制块链接成一个单向链表。链表中的所有控制块尚未与具体事件相关联,这个链表叫做空事件控制块链表。
每当应用程序中创建一个事件时,系统就会从链表中取出一个空事件控制块,并对它进行初始化以描述该事件。而当应用程序中删除一个事件时,就会将该事件的控制块归还给空事件控制块链表。