1.概述
在《rta-os系列介绍-task》部分我们介绍了任务分为基础任务与扩展任务,两者的主要区别为,扩展任务多了waiting状态,那waiting状态等待的是什么呢?其实就是我们今天要介绍的events(事件),当系统中的task或isr设置事件后,等待的任务将转到ready状态。当它成为最高优先级就绪任务时,rta-os将选择运行该task。
在autosar操作系统中,事件用于向任务发送信号信息,主要用于为扩展任务提供多个同步点。本文将对什么是事件,如何配置事件以及如何在运行时使用它们。events的使用场景大致如下图所示。
2. events配置
正常在应用中可配置的events的最大数量取决于硬件,而events需要配置的内容包括:名字、至少一个task使用及event mask。
设置事件时,必须同时指定任务。因此,例如,如果为名为task1的任务设置名为event0的事件,则这对任务task2的event0没有影响。
2.1 定义等待任务
在使用中,当我们声明某个task需要等待一个event时,系统将默认该任务为扩展任务,等待事件的扩展任务通常会自动启动(等待的时间满足后),并且任务永远不会终止。当任务开始执行时,rta-os将清除它拥有的所有事件。
3. 如何使用event
3.1 等待事件
任务的等待事件需要调用waitevent(eventmask) api,具体等待的eventmask需要关联到提前声明的内容。
waitevent()将事件作为其唯一参数。执行调用时,有两种可能:
1)事件暂未发生。这种情况下该task会进入等待状态,rta-os会运行ready状态中优先级最高的task。
2)事件已经发生。在这种情况下,任务将保持在运行状态,并将在waitevent()调用之后的语句中继续执行。
3.1.1 等待单一事件
要等待单个事件,只需将事件掩码名称传递给api调用。下面示例显示了任务如何使用等待事件。
#include task(extendedtask) {...waitevent(event1); /* task enters waiting state in api call ifevent1 has not happened *//* when event1 is set, extendedtask resumes here */...}
在autosar操作系统中,为处于挂起状态的任务设置事件是非法的。实际上,这意味着等待事件的任务结构通常是一个等待事件的有限循。
3.1.2 等待多个事件
因为autosar os事件只是一个位掩码(bit mask),所以用户可以通过按位设置一组位掩码,同时等待多个事件。
当任务等待多个事件时,当等待的任何一个事件发生时,它将恢复。当从等待多个事件恢复时,将需要确定发生了哪些事件。
#include task(extendedtask){ eventmasktype whathappened; while(true){ waitevent(event1|event2|event3); getevent(task1, &whathappened); if( whathappened & event1 ) { /* take action on event1 */ ... } else if( whathappened & event2 ) { /* take action on event2 */ ... } else if( whathappened & event3 ) { /* take action on event3 */ ... } }}
在autosar-os中,提供了getevent()的api,我们可以通过该api获知哪个事件已完成。
3.1.3 扩展任务的死锁
虽然autosar操作系统在关键部分的资源互斥中提供了免于死锁的自由,但在构建具有可能死锁的事件的系统时,仍不会受到保护。如果我们有相互设置和等待事件集的扩展任务,则两个(或更多)任务可能正在等待仅由其他正在等待的任务设置的事件。当然,即使存在死锁扩展任务,系统中的基本任务也不可能死锁。
下面的样例展示了扩展任务的死锁:
#include task(task1) { while (1) { waitevent(ev1); /* never reach here - deadlocked with task2! */ setevent(task2,ev2); }}task(task2) { while (1) { waitevent(ev2); /* never reach here - deadlocked with task1! */ setevent(task1,ev1); }}
os配置不获取哪些任务或isr设置了事件,只获取哪些任务可以等待事件。因此,rta-os不可能静态地确定扩展任务是否会死锁。采用下面的设计方法可能会避免类似问题:
•仅使用基本任务;
•分析代码,以表明在所有setevent()或waitevent()对的传递闭包上没有循环等待事件。
3.2 设置事件
通过setevent() api 来设置事件。
setevent()调用有两个参数,一个任务和一个事件掩码。对于指定的任务,setevent()调用设置事件掩码中指定的事件。该调用不会为共享事件的任何其他任务设置事件。
在调用setevent()时,可以按位或多个事件掩码来同时为任务设置多个事件。
无法为处于挂起状态的任务设置事件。因此,在设置事件之前,必须确保任务未挂起。您可以使用gettaskstate()api调用来实现这一点,但请注意,当为优先级高于调用方的任务调用此函数时,可能存在竞争条件。调用方可以在对api的调用和对结果的评估之间被抢占,并且被请求的任务的状态在中间时间内可能已经改变。
当扩展任务正在等待的任何一个事件被设置时,扩展任务将从等待状态移动到就绪状态。
如下任务显示了任务如何设置事件:
#include task(task1) { taskstatetype taskstate; /* set a single event */ setevent(task2, event1); /* set multiple events */ setevent(task3, event1 | event2 | event3); ... /* checking for the suspended state */ gettaskstate(task2,&taskstate); if (taskstate != suspended) { setevent(task2, event1); } ... terminatetask();}
多个任务可以同时等待同一个事件,然而从上面例子可以看出,事件没有广播机制,换句话说,不能通过调用一个api告诉所有等待的任务该事件已经发生。
此外,也可以通过alarms及调度表来设置事件。
3.2.1通过alarm设置事件
alarm可用于定期激活不终止的扩展任务。每次alarm到期时,都会设置该事件。等待事件的任务随后准备好运行。
3.2.2 通过带有到期点的调度表设置事件
调度表上的到期点可用于编程(a)非终止状态的扩展任务的定期激活。每次处理到期点时,都会设置事件。等待事件的任务随后准备好运行。
3.3 清除events
可以通过task或者isrs来设置event,但是event只能被其owner清除。
#include task(extendedtask){ eventmasktype whathappened; ... while( waitevent(event1|event2|event3)==e_ok ) { getevent(task1, & whathappened); if(whathappened & event1 ) { clearevent(event1); /* take action on event1 */ ... } else if( whathappened & (event2 | event3 ) { clearevent(event2 | event3); /* take action on event2 or event3*/ ... } }}
当某个任务等待某个事件,该事件发生,在后面时序再次对同一个事件调用waitevent()时,由于该事件仍处于set状态,会立即返回。因此,在再次调用等待事件前需要将之前已发生事件清除。
清除事件时调用clearevent api,被清除后的状态必须与事件掩码关联起来。
当某个任务被挂起时,其所拥有的event将被自动清除。
3.4 用基础任务模拟扩展任务
基础任务只能在任务执行的开始或结束时同步。
如还有其他同步节点需要时,可以通过event机制来实现。然而,扩展任务较基础任务占用资源更多,在资源限制的系统中,只能通过使用基础任务来进行 同步。
例如,如果任务构建为状态机(例如,使用c switch语句),则可以设置状态变量,发出terminatetask()调用并等待重新激活。如下样例代码显示了如何实现这一点。
#include /* create a state variable that remains in scope between taskactivations */uint8 state;task(task1) { switch (state) { case 0: /* synchronization point 0. */ state = 1; break; case 1: /* synchronization point 1. */ state = 2; break; case 2: /* synchronization point 2. */ state = 0; break; }terminatetask();}
4.本文总结
event是用于同步的实体,可用于扩展任务的等待内容;
同一个event可被不同的task引用;
event不具有广播机制,即无法将信息通知所有等待该event中的任务;
tasks,isrs及调度表都可以设置events。
如果时效性在系统中很重要,则所有扩展任务(任何等待事件的任务)的优先级必须低于基本任务。
输入电压线性调整率、输入电压线性变化时对输出电压的相对影响?
骁龙865或登场,综合性能可提升20%
预计2025年中国车联网市场空间将达到2190亿元
边缘计算的三大特点和边缘计算网关的技术优势
无线资源管理流程
Events(事件)概述、配置及使用方法
科技公司们在里约奥运会上将扮演什么角色
智能医疗是什么_智能医疗的组成
华为5G CPE Pro发布:家庭无线宽带成趋势
报告:2016年VR创企总融资超5.33亿美元
华为2019年中国企业级存储市场出货份额排名第一
一文详解超声波传感器的基础知识
盘点半导体行业走势分析及行业动态
OPPO A1带面部识别,还能拍出五千万像素的照片,仅售999元
运放电路设计中无源元件的选择
在计算机上正确安装最新版本的OpticStudio
GMIC大会:霍金表示对人工智能发展的担忧
H3C交换机命名规则
电力系统谐波的是怎么产生的?
2011年电子分销商大会(EDS)上Mouser荣获20项大奖