如何在AUTOSAR OS系统运行时使用事件Event呢?

汽车电子

2307人已加入

描述

正文

5.事件Event

在AUTOSAR OS系统中,事件用于向任务发送信号信息。本节解释事件是什么,如何配置它们以及如何在运行时使用它们。

事件可用于为扩展任务提供多个同步点。同步的可视化如图5.1所示。

扩展任务可以等待事件,这将导致任务进入等待状态。当系统中的任务或ISR设置事件时,等待任务将进入就绪状态。当它成为最高优先级的就绪任务时,RTA-OS将选择它来运行。

事件由与其关联的扩展任务拥有。通常,扩展任务将作为一个无限循环运行,其中包含对其拥有的事件的一系列受保护的等待调用。因此,事件机制允许构建事件驱动的状态机。

如果计时行为在您的系统中很重要,那么所有扩展任务(换句话说,等待事件的任何任务)的优先级必须低于基本任务。

ISR

图5.1 事件的可视化

5.1 配置事件Configuring Event

使用rtaoscfg配置事件。应用程序中可以存在的最大事件数由目标硬件决定。查阅目标/编译器端口指南,可以了解每个任务可以有多少个事件。

当声明事件时,它必须具有:

•名字。

  名称仅用于在配置时指示事件的目的。

•至少有一个任务使用它。

•事件掩码。

  这可以由RTA-OS自动分配。

在rtaoscfg中指定的事件名称在运行时用作事件掩码的符号名称。掩码是一个N位向量,其中N是一个任务可以等待的最大事件的最大数量。set位标识一个特定的事件。

事件名称在运行时用作掩码的符号名称。通过选择表示事件的位来配置掩码。图5.2显示了一个名为WakeUp的事件已经被声明,它将使用事件掩码中的第9位。除非确实需要分配一个特定的位位置,否则最好让RTA-OS来确定掩码值。这允许它优化bit的打包( optimize the packing of the bits),从而节省内存。

ISR

图5.2:配置事件掩码

如果一个事件由多个任务使用,则每个任务都有自己的单独副本。设置事件时,必须同时指定任务。因此,例如,如果您为一个名为t3的任务设置了一个名为Event2的事件,这对任务t4的Event2没有影响。

5.1.1 定义等待事件 Defining Waiting Tasks

使用rtaoscfg选择等待任务。如果声明一个等待事件的任务,则意味着该任务将自动被视为扩展任务。

图5.3显示了已经声明了一个事件WakeUp,并且任务TaskC和TaskD已经配置为等待该事件。

等待事件的扩展任务通常会自动启动,并且任务永远不会终止。当任务开始执行时,RTA-OS将清除它拥有的所有事件。

ISR

图5.3:选择等待事件的任务

5.2 等待事件 Waiting on Events

任务使用WaitEvent(EventMask) API调用等待事件。EventMask必须与rtaoscfg中声明的EventMask对应。

WaitEvent()将事件作为其唯一参数。当调用执行时有两种可能:

1)该事件尚未发生。在这种情况下,任务将进入等待状态,RTA-OS将在就绪状态下运行最高优先级的任务。

2)事件已发生。在这种情况下,任务保持在运行状态,并将在WaitEvent()调用之后的语句中继续执行。

5.2.1 单个事件Single Events

等待单个事件,只需将事件掩码名称传递给API调用。示例5.1显示了任务如何等待事件。

 

#include 
TASK(ExtendedTask) {
  ...
  WaitEvent(Event1); /* Task enters waiting state in API call if Event1
has not happened */
/* When Event1 is set, ExtendedTask resumes here */
...
}

 

Example 5.1: Waiting on an Event

在AUTOSAR操作系统中,为处于挂起状态的任务设置事件是非法的。在实践中,这意味着等待事件的任务结构通常是一个等待事件的无限循环,如例5.2所示。

 

#include 
TASK(ExtendedTask){
  /* Entry state */
  while(true){
  WaitEvent(Event1);
  /* State 1 */
  WaitEvent(Event2);
  /* State 2 */
  WaitEvent(Event3);
  /* State 3 */
  }
/* Task never terminates */
}

 

Example 5.2: Simple 3-state State Machine with Events

5.2.2 多个事件Multiple Events

因为AUTOSAR OS事件只是一个位掩码,所以可以通过按位顺序排列一组位掩码来同时等待多个事件。

当任务等待多个事件时,当等待的任何一个事件发生时,它将被恢复。当从等待多个事件中恢复时,需要计算出发生了哪个(或多个)事件。

 

#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 */
    ...
    }
  }
}

 

Example 5.3: Waiting on Multiple Events

AUTOSAR OS提供了GetEvent() API调用,允许获取为任务设置的当前事件集。

例5.3展示了任务如何同时等待多个事件,然后在恢复时识别哪些事件已被设置。

5.2.3 扩展任务的死锁 Deadlock with Extended Tasks

虽然AUTOSAR OS在临界区互斥中提供了免于死锁的方法(参见第4章),但不能避免使用可能死锁的事件构建系统。如果有相互设置和等待事件集的扩展任务,那么可能会有两个(或更多)任务正在等待事件,而这些事件仅由正在等待的其他任务设置。当然,系统中的基本任务不可能死锁,即使存在死锁的扩展任务。

例5.4展示了两个任务,如果没有其他任务设置Ev1或Ev2,它们将死锁。

操作系统配置不捕获哪些任务/ ISR设置事件,只捕获哪些任务可以等待事件。因此,RTA-OS不可能静态地确定扩展任务是否会死锁。然而,以下设计方法可能会有所帮助:

•只使用基本任务

•分析代码,以显示在所有SetEvent()/WaitEvent()对的传递性闭包上没有循环等待事件

 

#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)
  }
}

 

Example 5.4: Deadlock with Extended Tasks

5.3 设置事件Setting Events

使用SetEvent() API设置事件。

SetEvent()调用有两个参数,一个任务和一个事件掩码。对于指定的任务,SetEvent()调用设置事件掩码中指定的事件。该调用不为共享事件的任何其他任务设置事件。可以在调用SetEvent()时按位或多个事件掩码,以同时为任务设置多个事件

无法为处于挂起状态的任务设置事件。因此,在设置事件之前,必须确保任务没有挂起。

可以使用GetTaskState() API调用来实现这一点,但请注意,当对比调用者优先级更高的任务调用此方法时,存在潜在的竞争条件。调用者可能在调用API和评估结果之间被抢占,并且被请求的任务的状态可能在这段时间内发生了变化。

当扩展任务正在等待的任何一个事件被设置时,扩展任务将从等待状态移动到就绪状态。

例5.5展示了任务如何设置事件。

多个任务可以等待一个事件。但是,从例5.5中可以看到,事件没有广播机制。换句话说,无法通过单个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();
}

 

Example 5.5: Setting Events

5.3.1 使用报警器设置事件Setting Events with an Alarm

警报可用于定期激活不终止的扩展任务。每次告警过期,都会设置该事件。等待事件的任务将准备好运行。

5.3.2 通过调度表的Expiry Point设置事件Setting Events with a Schedule Table Expiry Point

调度表上的到期点可用于扩展任务的定期激活。每次处理过期点时,都会设置事件。等待事件的任务将准备好运行。

5.4 清除事件Clearing Events

事件可以由任何任务或ISR设置,但只能由事件所有者清除。

当一个任务等待一个事件时,事件发生了,那么对同一事件的WaitEvent()的后续调用将立即返回,因为事件仍然是设置的。

在等待事件再次发生之前,必须清除该事件最后一次发生的事件。

使用ClearEvent(EventMask) API调用清除事件。EventMask必须与声明的EventMask对应。

例5.6展示了任务通常如何使用ClearEvent()。

当任务终止时,它拥有的所有事件将自动清除。

 

#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*/
    ...
    }
  }
}

 

Example 5.6: Clearing Events

5.5 用基本任务模拟扩展任务 Simulating Extended Tasks with Basic Tasks

基本任务只能在任务执行开始或结束时同步。

如果需要其他同步点,则事件机制提供了一种方法。然而,扩展任务通常比基本任务有更大的开销。在资源受限的系统上,只能使用基本任务来构建同步。

例如,如果将任务构建为状态机(例如使用C switch语句),则可以设置状态变量,发出TerminateTask()调用并等待重新激活。例5.7展示了如何实现这一点。

 

#include 
/* Create a "State" variable that remains in scope between task
activations */
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();
}

 

Example 5.7: Multiple Synchronization Points in a Basic Task

5.6 小结

•事件是可以由扩展任务等待的同步对象。

•一个事件可以被多个任务使用。

•设置一个事件不是一个广播机制来通知所有正在等待的任务。

•任务,ISR,Alarm和调度表可以设置事件。






审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分