分类: BSD
2012-10-12 10:45:47
1,mian()
{
初始化;
process_init();
process_start(&etimer_process, NULL);
autostart_start(autostart_processes);
while(1)
{
..........
process_run();
.........
}
2,程序的主体部分。
#include "contiki.h"
#include "debug-uart.h"
/*步骤2:用PROCESS宏声明进程执行主体,并定义进程*/
PROCESS(example_1_process,"Example 1");//PROCESS(name, strname)
PROCESS(example_2_process,"Example 1");
/*步骤3:用AUTOSTART_PROCESSES宏让进程自启动*/
AUTOSTART_PROCESSES(&example_1_process,&example_2_process);//AUTOSTART_PROCESSES(...)
/*步骤4:定义进程执行主体thread*/
PROCESS_THREAD(example_1_process,ev,data)//PROCESS_THREAD(name, ev, data)
{
PROCESS_BEGIN(); /*代码总是以宏PROCESS_BEGIN开始*/
/*example_1_process的代码*/
PROCESS_END(); /*代码总是以宏PROCESS_END结束*/
}
PROCESS_THREAD(example_2_process,ev,data)
{
PROCESS_BEGIN();
/*example_2_process的代码*/
PROCESS_END();
}
先声明,然后调用AUTOSTART_PROCESSES来初始化一个全局数组,这是一个宏,在预处理阶段就会处理掉,在main()执行前,数组已经初始化完毕。然后在主程序里执行到 autostart_start,它会调用 process_start,process_start 会将此进程加入process_list,并初始化此进程的lc=0,然后调用了process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);此时将一个PROCESS_EVENT_INIT 事件传了过来,而arg=NULL。 process_post_synch() 调用call_process()将参数 传递过来,call_process 改变下状态,就开始执行
p->state = PROCESS_STATE_CALLED;
ret = p->thread(&p->pt, ev, data);
由于contiki是CRT机制,所以会一直运行到此process阻塞或者退出
if(ret == PT_EXITED ||
ret == PT_ENDED ||
ev == PROCESS_EVENT_EXIT) {
exit_process(p, p);
} else {
p->state = PROCESS_STATE_RUNNING;
}
如果要退出,调用exit_process,如果是阻塞,设置下状态就会返回了,返回到process_post_synch 找出上次正在执行的process,然后返回到调用process_post_synch的位置,继续执行,process_current = caller;就绪下去,如果这个进程也阻塞,则再次先前返回,找到更先前的process_current。。。。。。类似与递归的概念, 一层层入栈 入栈,执行完之后再出栈,不同点在于,事件机制可以在出栈的过程再次入栈,就在一个栈里面来回捣鼓
接下来给出三种程序基本结构(即顺序、选择、循环)的模式。
二、顺序&选择&循环
2.1 顺序
PROCESS_BEGIN();
(*...*)
PROCESS_WAIT_UNTIL(cond1);//注1
(*...*)
PROCESS_END();
2.2 循环
PROCESS_BEGIN();
(*...*)
while(cond1)
PROCESS_WAIT_UNTIL(cond1 orcond2);//注1
(*...*)
PROCESS_END();
2.3 选择
PROCESS_BEGIN();
(*...*)
if(condtion)
PROCESS_WAIT_UNTIL(cond2a);//注1
else
PROCESS_WAIT_UNTIL(cond2b);//注1
(*...*)
PROCESS_END();
注1:这里不一定非得用宏PROCESS_WAIT_UNTIL,事实上有很多选择,比如宏PROCESS_WAIT_EVENT_UNTIL(c)、宏PROCESS_WAIT_EVENT()、宏PROCESS_YIELD_UNTIL(c)等(请参见本文第三部分),实际编程应根据实际情况加以选择。
三、挂起进程相关API
3.1 概述
表1给出挂起进程相关API的功能描述,事实上,实际编程所关心的是,什么时候继续执行宏后面的内容,3.2~3.6给出了详见分析。
表1 Contiki挂起进程相关API[1]
3.2 PROCESS_WAIT_EVENT和PROCESS_YIELD
从代码展开来看,宏PROCESS_WAIT_EVENT和宏PROCESS_YIELD实现的功能是一样的(或者说PROCESS_WAIT_EVENT只是PROCESS_YIELD的一个别名),只是两种不同的描述。也就是说当PT_YIELD_FLAG为1时(即该进程再次被调度的时候,想想PROCESS_BEGIN宏包含语句PT_YIELD_FLAG=1),才执行宏后面的代码,否则返回。代码展开如下:
#define PROCESS_WAIT_EVENT()PROCESS_YIELD()
#define PROCESS_YIELD()PT_YIELD(process_pt)
#define PT_YIELD(pt) \
do
{ \
PT_YIELD_FLAG =0; \
LC_SET((pt)->lc); \
if(PT_YIELD_FLAG ==0)
{ \
returnPT_YIELDED; \
} \
}while(0)
3.3 PROCESS_WAIT_EVENT_UNTIL和PROCESS_YIELD_UNTIL
根3.2类似,宏PROCESS_WAIT_EVENT_UNTIL和宏PROCESS_YIELD_UNTIL是一组,在3.2的基础是增加了额外的一个条件,也就是说当PT_YIELD_FLAG为1且条件为true时(即进程再次被调度的时候,条件为true,因为PROCESS_BEGIN宏已包含语句PT_YIELD_FLAG),才执行宏后面的代码,否则返回。代码展开如下:
#define PROCESS_WAIT_EVENT_UNTIL(c)PROCESS_YIELD_UNTIL(c)
#define PROCESS_YIELD_UNTIL(c)PT_YIELD_UNTIL(process_pt,c)
#define PT_YIELD_UNTIL(pt,cond) \
do
{ \
PT_YIELD_FLAG =0; \
LC_SET((pt)->lc); \
if((PT_YIELD_FLAG ==0)||!(cond))
{ \
returnPT_YIELDED; \
} \
}while(0)
3.4 PROCESS_WAIT_UNTIL和PROCESS_WAIT_WHILE
从代码展开来看,宏PROCESS_WAIT_UNTIL和宏PROCESS_WAIT_WHILE判断的条件相反,PROCESS_WAIT_UNTIL宏当条件为真时(即某个事件发生),执行宏后面的内容。而PROCESS_WAIT_WHILE宏当条件为假时,执行宏后面的内容(即当条件为真时,阻塞该进程)。
/*PROCESS_WAIT_UNTIL宏展开*/
#define PROCESS_WAIT_UNTIL(c)PT_WAIT_UNTIL(process_pt,c)
/*PROCESS_WAIT_WHILE宏展开*/
#define PROCESS_WAIT_WHILE(c)PT_WAIT_WHILE(process_pt,c)
#define PT_WAIT_WHILE(pt,cond)PT_WAIT_UNTIL((pt),!(cond))
/*PT_WAIT_UNTIL宏展开*/
#define PT_WAIT_UNTIL(pt,condition) \
do
{ \
LC_SET((pt)->lc); \
if(!(condition))
{ \
returnPT_WAITING; \
} \
}while(0)
3.5 PROCESS_PT_SPAWN
PROCESS_PT_SPAWN用于产生一个子protothread,若执行完thread并退出PT_EXITED,则继续执行宏PROCESS_PT_SPAWN后面的内容。宏一层层展开如下:
#define PROCESS_PT_SPAWN(pt,thread)PT_SPAWN(process_pt,pt,thread)
#define PT_SPAWN(pt,child,thread) \
do
{ \
PT_INIT((child)); \
PT_WAIT_THREAD((pt),(thread)); \
}while(0)
#define PT_WAIT_THREAD(pt,thread)PT_WAIT_WHILE((pt),PT_SCHEDULE(thread))
#define PT_WAIT_WHILE(pt,cond)PT_WAIT_UNTIL((pt),!(cond))
#define PT_SCHEDULE(f)((f)<PT_EXITED)
3.6 PROCESS_PAUSE
宏PROCESS_PAUSE用于向进程传递事件PROCESS_EVENT_CONTINUE,被挂起了宏展开如下如下:
#define PROCESS_PAUSE()
do
{ \
process_post(PROCESS_CURRENT(),PROCESS_EVENT_CONTINUE,NULL); \
PROCESS_WAIT_EVENT(); \
}while(0)
这个很好理解,就是自己给自己发送了个事件,PROCESS_EVENT_CONTINUE,这个不过是标示而已,然后系统会去执行其他的代码,直到do_event时,此进程收到自己发给自己的事件,就可以继续运行了。也就是暂停了以下,就继续运行下去了。
3.7 PROCESS_WAIT_EVENT_UNTIL与PROCESS_WAIT_UNTIL区别
从上述3.3和3.4代码展开可以看出,宏PROCESS_WAIT_EVENT_UNTIL和宏PROCESS_WAIT_UNTIL的区别在于:
PROCESS_WATI_EVENT_UNTIL 是一定会导致进程阻塞的,即使里面条件是满足的,也会阻塞到下次调度。这个API首先要求,要阻塞,此进程下面代码是无论如何不能执行下去了,必须阻塞,但是再次执行下去的条件是,有事件来了,并且附加条件也满足,才可以运行了。
PROCESS_WAIT_UNTIL,它是说,进程并非已经达到了不能执行的地步,只要条件是满足的,那么就会执行下去,不一定会导致阻塞。