Chinaunix首页 | 论坛 | 博客
  • 博客访问: 393227
  • 博文数量: 87
  • 博客积分: 1171
  • 博客等级: 少尉
  • 技术积分: 1068
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-19 14:34
文章分类

全部博文(87)

文章存档

2014年(10)

2013年(24)

2012年(53)

我的朋友

分类: 嵌入式

2012-10-12 20:03:41

Contiki学习笔记:protothread状态 (转)

一、PT四种状态

#define PT_WAITING 0 

#define PT_YIELDED 1 

#define PT_EXITED  2 

#define PT_ENDED   3

Contiki事件相关函数与protothread状态关系如下图(注-没有包含所有函数):

1.1 PT_WAITING

宏PROCESS_WAIT_UNTIL(c)用到了PT_WAITING,该宏用于挂起进程直到条件c成立,源码如下:

#define PROCESS_WAIT_UNTIL(c)PT_WAIT_UNTIL(process_pt,c)

宏PROCESS_WAIT_UNTIL(c) 不保证进程会让出执行权,源码注释如下:

This macro does not guarantee that the process yields, and should therefore be used with care. In most cases, PROCESS_WAIT_EVENT(),PROCESS_WAIT_EVENT_UNTIL(), PROCESS_YIELD() or PROCESS_YIELD_UNTIL() should be used instead.

 

 

宏PT_WAIT_UNTIL并不保证进程会被挂起,当条件为真时,继续执行后续内容。宏展开如下:

#define PT_WAIT_UNTIL(pt,condition)     \

  do

  {                        \

    LC_SET((pt)->lc);                \

    if(!(condition))

    {                \

      returnPT_WAITING;            \

    }                        \

  }while(0)

在PT_RESTART宏也用到了PT_WAITING,源码如下:

 

 

 

1.2 PT_YIELDED

(1) PT_YIELD_FLAG = 0 

    表示条件不满足,主动让出执行权。PT_END(pt)、PT_YIELD(pt) 、PT_YIELD_UNTIL(pt, cond)将PT_YIELD_FLAG设置成0

(2) PT_YIELD_FLAG =1

    表示条件满足,继续执行后续代码。在PT_BEGIN(pt)将PT_YIELD_FLAG设置成1

为了便好理解PT_YIELD_FLAG,以PROCESS_WAIT_EVENT宏作为分析对象,源代码如下:

#definePROCESS_WAIT_EVENT()PROCESS_YIELD()

#definePROCESS_YIELD()PT_YIELD(process_pt)

#definePT_YIELD(pt)\

do{\

  PT_YIELD_FLAG =0;\


  LC_SET((pt)->lc);\


  if(PT_YIELD_FLAG ==0)\

  {


      returnPT_YIELDED;\

  }\

}while(0)


#defineLC_SET(s)=__LINE__;case__LINE__:  //保存程序断点,下次再运行该进程直接跳到case __LINE__

    PROCESS_WAIT_EVENT宏用于等待一个事件发生,如果检测到PT_YIELD_FLAG为1,就继续执行PROCESS_WAIT_EVENT宏后面的代码。若PT_YIELD_FLAG为0了,就直接返回PT_YIELDED,从博文《Contiki学习笔记:启动一个进程process_start》第三部分call_process函数,可知并没有退出进程,只是把进程状态设为PROCESS_STATE_RUNNING。call_process(struct process *p, process_event_t ev, process_data_t data)函数部分代码如下:

ret =p->thread(&p->pt,ev,data);//才真正执行PROCESS_THREAD(name, ev, data)定义的内容

if(ret ==PT_EXITED ||ret ==PT_ENDED ||ev ==PROCESS_EVENT_EXIT)

{

  exit_process(p,p);//如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出

}

else

{

  p->state=PROCESS_STATE_RUNNING;//进程挂起等待事件

}

    这有个疑问,什么时候把PT_YIELD_FLAG 设为1,才能以继续执行PROCESS_WAIT_EVENT宏后面的代码。我也纳闷,在整个源码,只找到PT_BEGIN宏将其设1。从源码分析,该进程没有机会执行PROCESS_WAIT_EVENT宏后面的内容,只有其他进程传递一个事件PROCESS_EVENT_EXIT让其退出,即process_post(&hello_world_process, PROCESS_EVENT_EXIT, NULL)。但实际编辑,只要向该进程传递一个普通事件,即可执行PROCESS_WAIT_EVENT宏后面的代码。很是不解,求助中……。(实例见附录)

    上述问题已解决(2012-03-21)。当进程再次被调度的时候,会执行PROCESS_BEGIN,而该宏包含两条语句:其一,PT_YIELD_FLAG=1;其二,switch(pt->lc),从而转到被挂起的地方case __LINE__继续执行。

1.3 PT_EXITED

宏PROCESS_EXIT(让当前进程退出,自己结束自己的生命)用到了PT_EXITED,源码如下:

#define PT_EXIT(pt)                \

  do

  {                        \

    PT_INIT(pt);                \

    returnPT_EXITED;            \

  }while(0)

    执行进程主体thread时(call_process函数),会返回结果,如果结果是PT_EXITED或者1.4的PT_ENDED,则进程退出(exit_process函数),部分源码如下:

ret =p->thread(&p->pt,ev,data);//才真正执行PROCESS_THREAD(name, ev, data)定义的内容

if(ret ==PT_EXITED ||ret ==PT_ENDED ||ev ==PROCESS_EVENT_EXIT)

{

  exit_process(p,p);//如果返回值表示退出、结尾或者遇到PROCESS_EVENT_EXIT,进程退出

}

1.4 PT_ENDED

这个就不陌生了,在宏PROCESS_END展开就有这么一句return PT_ENDED,一层层展开如下:

#define PROCESS_END()PT_END(process_pt)


#define PT_END(pt)LC_END((pt)->lc);PT_YIELD_FLAG =0;\

                   PT_INIT(pt);returnPT_ENDED;}

二、编程指南

    理解上述内容后,相信对多个进程间事件如何交互比较清楚了,在实际编程过程,可以参考如下两个网址,分别列出了pt及process头文件的API:

[1] 

[2] 


附PROCESS_EVENT_EXIT测试用例:

//filename:process_wait_event_test.c

#include "contiki.h"

#include "debug-uart.h"


PROCESS(hello_world_process,"Hello world");

PROCESS(post_event_process,"Post event");


AUTOSTART_PROCESSES(&hello_world_process,&post_event_process);


PROCESS_THREAD(hello_world_process,ev,data)

{

  PROCESS_BEGIN();

  usart_puts("Hello, world!\n");

  

  while(1)

  {

    //usart_puts("while.Before wait event!\n");

    PROCESS_WAIT_EVENT();

    usart_puts("Have been posted an event!\n");

  }

  

  PROCESS_END();

}



PROCESS_THREAD(post_event_process,ev,data)

{

  PROCESS_BEGIN();

  usart_puts("Post event!\n");

  

  staticprocess_event_t event_post;

  event_post =process_alloc_event();

  

  process_post(&hello_world_process,event_post,NULL);

  //process_post(&hello_world_process, PROCESS_EVENT_EXIT, NULL);

  

  PROCESS_END();

}

 

 

 

http://blog.chinaunix.net/uid-9112803-id-2982648.html

阅读(894) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~