从VxWorks 5.5开始,提供了新的任务间同步通信的机制----事件,事件可用于任务和中断服务程序ISR之间、任务和任务之间、任务和VxWorks资源之间进行通信。 任务用函数eventReceive()来接收它关心的事件,用eventSend()来向另一个任务发送事件。

先来看第一个例子:

 
 
void eventRoute1(void* param)  
{  
     int task_id = (int)param;  
     eventSend(task_id , VXEV01);  
         
}  
void tryEvent()  
{  
     int id = taskIdSelf();  
     taskSpawn("vxEvent1", 150, VX_FP_TASK, 30000, (FUNCPTR)eventRoute1, id,0,0,0,0,0,0,0,0,0 );  
     eventReceive(VXEV01, EVENTS_WAIT_ALL, WAIT_FOREVER, 0);  
}  
 

在tryEvent中启动一个任务,然后调用eventReceive通过设置EVENTS_WAIT_ALL来等待VXEV01事件的发生,子任务中调用eventSend向初始任务发送事件VXEV01,从而触发初始任务继续执行。

从这个例子,很多人也许会觉得事件跟信号量功能一样,没有太多意义。其实上面体现的功能只是事件的冰山一角,让我们慢慢来一窥全貌吧。

那么,事件有哪些特点呢?

第一,从上面的例子已经可以看出,使用事件时不需要创建任何对象,所以它是一种更轻量级的同步通信机制。因为每一个任务都有一个32位事件寄存器,其中高8位由VxWorks系统保留,开发者可以使用低24位(VXEV01~VXEV24),每一位表示一种事件。

第二,使用事件可以等待多个事件的发生,这里的多个事件发生的关系,可以是“与”也可以是“或”,在eventReceive方法中可以指定EVENTS_WAIT_ANY或EVENTS_WAIT_ALL,比如等待VXEV01或VXEV02之一的发生:

eventReceive(VXEV01 | VXEV02, EVENTS_WAIT_ANY, WAIT_FOREVER, 0);

个人认为这是非常有用的一点,毕竟如果要自己实现多事件结合并可控制超时时间的话,可以说并非那么简单,而且性能也会有问题。

第三,除了上述例子中eventReceive和eventSend的使用外,事件还可用于任务跟VxWorks资源之间进行通信,这里所谓的资源有信号量,消息队列等。

比如再看第二个例子(假设已创建了sem_ev1和sem_ev2两个信号量):

 
 
void eventRoute1(void* param)  
{  
     semGive(sem_ev1);  
}  
     
void eventRoute2(void* param)  
{  
     semGive(sem_ev2);  
}  
void tryEvent()  
{  
     semEvStart(sem_ev1, VXEV01, EVENTS_SEND_ONCE);  
     semEvStart(sem_ev2, VXEV02, EVENTS_SEND_ONCE);  
     
     taskSpawn("vxEvent1", 150, VX_FP_TASK, 30000, (FUNCPTR)eventRoute1, 0,0,0,0,0,0,0,0,0,0 );  
     taskSpawn("vxEvent2", 150, VX_FP_TASK, 30000, (FUNCPTR)eventRoute2, 0,0,0,0,0,0,0,0,0,0 );  
     
     eventReceive(VXEV01 | VXEV02, EVENTS_WAIT_ALL, WAIT_FOREVER, 0);  
     
     semEvStop(sem_ev1);  
     semEvStop(sem_ev2);  
}  
 

跟资源通信,需要把对应资源注册到特定事件,如上例中是通过semEvStart把信号量sem_ev1和sem_ev2分别注册到事件VXEV01和VXEV02,然后semGive信号量被释放且可用时,对应注册的事件会被触发。

第四,前面说到semGive信号量被释放且可用时,对应注册的事件会被触发,这里所谓可用的含义是,semGive释放信号量同时没有其他任务正在锁定该资源,也就是该时间点该资源可用时,才会触发事件。但不能保证该资源在事件被触发后还可用,因为后续有可能又被其他任务锁定。

第五,如果相关被注册到事件的资源被删除时,通过eventReceive等待该事件的任务会自动被触发,也就是说semDelete和msgQDelete会触发该资源注册过事件。但是需要注意的是,当调用semDelete时,任务执行于semEvStart和eventReceive之间的话,则后续eventReceive会被阻塞。

总上所述,VxWorks中,事件提供了非常丰富的功能,在实际应用场景中它的一些特性可以使很多复杂的事情变得极其简单。