1.接口函数的定义与调用
我们知道,接口由一组被称为命令或事件的函数组成,组件必须实现它提供接口中的命令以及使用接口中的事件。因此,在模块实现部分就要定义接口函数。不同的接口中可能存在相同的命令名字或事件名字,为了保证函数定义的唯一性,在模块实现中定义接口函数时,函数名字由接口名字与接口中的命令或事件名字组合而成,中间使用“.”连接到一起,避免了不同接口中可能存在的同名命令或事件带来的混乱。下面的程序是模块PowerupC和RealmainP的定义,关键字implementation后面大括号中的代码是模块实现。由于PowerupC使用Boot接口,Boot接口中有一个事件booted,因此,模块PowerupC中必须定义接口函数event void Boot.booted(){…}。接口函数名字由接口名字Boot与事件名字booted联合组成。当接口Boot的提供者RealmainP向模块PowerupC通知系统已经启动的事件(signal Boot.booted())时,就调用了模块PowerupC中的Boot.booted()函数,运行模块PowerupC中Boot.booted()函数,会进一步调用接口命令Leds.Leds0on(),打开相应的二极管。从模块PowerupC以及RealmainP中的例子可以看到,模块实现部分除了接口函数的定义外,接口函数调用也与C中函数调用的用法不同,需要使用新的关键字。
●调用接口命令函数时使用关键字call,如模块PowerupC中的调用接口命令语句:
●调用接口事件函数使用关键字signal,如模块RealmainP中的调用接口事件语句:
在上述的描述中,读者自然会产生这样一个疑问:为什么在模块RealMainP中运行signal Boot.booted()语句,会去调用模块PoweupC中定义的接口函数Boot.booted()呢?这些函数名字的调用关系是如何绑定的呢?答案是:只需要将接口(比如这里的Boot)的提供者和使用者连接上就可以了。连接接口的使用者和提供者是配件的工作,我们将在下一节讨论。模块PowerupC和RealmainP的定义代码如下:
2.通过接口函数传递参数(https://www.xing528.com)
组件间交互的唯一方式是通过函数调用,这里的函数通常是指接口函数。通过接口函数在组件之间传递参数的方式有两种:赋值和引用(指针)。第一种方式是将数据复制到栈。在这种方式下,被调用函数可以自由存放和修改数据。第二种方式是在调用函数和被调用函数之间共享指针变量。在这种方式下,为了避免内存数据损坏和内存空间泄露,两个组件都要谨慎管理对数据的访问,因此应该尽量减少数据共享情况的出现。
减少数据共享的一种简单的方法是在模块变量中不存放指针。在一些抽象数据组件中就使用了这种方法。抽象数据组件主要包括通用模块和带有指针参数命令的通用接口。将数据封装在组件中,使用接口中提供的命令来访问这些数据。由于使用指针作为参数的命令或者事件的持续时间是有限的,因此数据共享的时间也很短暂,减少了数据共享带来的问题,但仍然会出现数据不一致的问题。
这种方法在分阶段调用中不适用。考虑下面的接口Send中的函数send和sendDone。
接口Send也是一个分阶段接口。发送分组的Send接口中具有4个命令和1个事件。Send接口的使用者调用Send.send()命令,即调用下层组件发送分组,当下层组件发送完分组后,会调用该接口中的sendDone()事件通知上层组件。更具体地说,为了发送一个数据分组,接口Send的使用者调用命令Send.send(),返回值是SUCCESS,表明已经将指向数据分组的指针(msg)传递给了接口的提供者(被调用者)。被调用者将在一个变量中存储该指针,改变状态并直接返回。如果接口Send的使用者在将数据分组传递给接口的提供者后修改了数据包,则数据分组可能会被损坏。例如,接口提供者中的调用函数在计算完整个数据分组的校验和后发送该分组,此后又修改了该数据分组中某些字段的值,导致数据分组的校验和不再与该分组匹配,在这种情况下,接收该数据分组的节点会认为收到一个错误的分组而丢弃它,造成了资源的浪费。
为了避免上述问题,在TinyOS中提出了“所有权”规则:任何时间存放变量的内存块应归唯一的某个模块所有。在上述例子中,接口Send的使用者调用了命令Send.send(),实际上就将指针msg所指的内存块的所有权从调用者(接口的使用者)交给了被调用者(接口的提供者),因此,在该分组真正发送完毕之前,即收到Send.sendDone()事件之前,接口Send的使用者不是该内存块的所有者,所以不要对该内存块进行操作,这样可以避免共享指针带来的损坏内存数据的问题。为了充分利用内存,避免内存泄露问题,还应在Send.sendDone()事件中将相应的内存块指针作为参数传递回接口的使用者,将内存块的所有权返还给它原来的所有者,使得原来的所有者可以继续使用该内存块。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。
