Contiki:Protothread切换机制理解

在Contiki中,protothread的切换,实质是函数调用,通过call_process()函数调用protothread函数体的函数指针,来切换protothread,即ret = p->thread(&p->pt, ev, data);这里的p->thread指向的就是定义protothread的函数。而由于此函数中代码基本都是在PT_BEGIN和PT_END之间(宏展开后是一个完整的switch语句),所以对于保存状态的就是在本函数中运行的位置,通过__LINE__保存上一次运行到哪里,然后当再次调用这个protothread时,就可以通过switch跳到上一次执行的地方继续执行。

A protothread is driven by repeated calls to the function in which the protothread is running. Each time the function is called, the protothread will run until it blocks or exits. Thus the scheduling of protothreads is done by the application that uses protothreads.(contiki-2.6/doc/pt-doc.txt)

这和其他系统的任务切换概念是不一样的,像uCOS,Linux都是保存堆栈,保存寄存器信息,保存一个完整的任务运行状态下一次继续重复上一次的运行。而Contiki的这种Protothread更像是函数的调用,不过和一般的函数调用不一样的是,它下一次调用时进入函数运行的起点不是都一样,而是又上一次退出时(pt)->lc的值来决定。而且这时寄存器的值都不是上一次退出函数时的值,而是对于本次运行都是无用的,这也就是为什么Contiki在protothread中不建议使用局部变量的原因,因为只要退出本次protothread,下次重新运行时,即使是知道了上一次的退出时的位置,局部变量的值依然是未知的,因为没有保存。同时由于protothread使用switch语句实现,如果使用不当可能破坏protothread的跳转,这是为什么在protothread中不建议使用switch的原因。

当然,还有一种protothread的切换机制是使用goto语句实现的,这种实现机制下,使用switch语句是没有问题的。只是这种方式是基于GCC 编译器对于C的扩展实现的。

* This implementation of local continuations is based on a special
* feature of the GCC C compiler called "labels as values". This
* feature allows assigning pointers with the address of the code
* corresponding to a particular C label.

使用前要明确知道运行时系统使用的是哪一种切换机制。由于goto是基于GCC的特性,所以如果不是用GCC编译,就不用去尝试switch语句了。

A protothread runs within a single C function and cannot span over other functions.A protothread may call normal C functions, but cannot block inside a called function(contiki-2.6/doc/pt-doc.txt)

Contiki不能在被调函数中使用Block这样会造成protothread跳转错误。本质是因为使用switch语句或者goto语句。因为switch和goto语句有自己的限制,他们只能在函数内跳转,不能进行全局跳转。因为此,它们在实现BLOCK时,返回使用的是return语句,在被调函数中调用PT_WAIT_UNTIL也无法实现protothread的返回。

关于protothread的使用及注意事项在contiki-2.6/doc/pt-doc.txt说的很详细,仔细阅读下。

总之,不能使用以前的操作系统的概念来使用Contiki,要学着适应这种操作系统。每一种操作系统都有其最适合的地方,Contiki是为WSN设计的,对于WSN的实现而言,它应该是很优秀的。至于做其他的实现,不必为了用Contiki而用Contiki,选择适合的操作系统是我们需要做的,不必去苛求系统。


你可能感兴趣的:(Contiki:Protothread切换机制理解)