以contiki 2.6中最简单的example/hello_world.c为例。程序的代码如下:
-
PROCESS(hello_world_process, "Hello world process");
-
AUTOSTART_PROCESSES(&hello_world_process);
-
/*---------------------------------------------------------------------------*/
-
PROCESS_THREAD(hello_world_process, ev, data)
-
{
-
PROCESS_BEGIN();
-
-
printf("Hello, world\n");
-
-
PROCESS_END();
- }
PROCESS
PROCESS(hello_world_process, "Hello world process"); 展开代码如下:-
static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data);
- struct process hello_world_process = { ((void *)0), "Hello world process", process_thread_hello_world_process};
-
struct process hello_world_process = { ((void *)0), "Hello world process", process_thread_hello_world_process};
-
struct process * const autostart_processes[] = {&hello_world_process, ((void *)0)};
-
-
static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data)
-
{
-
{
-
char PT_YIELD_FLAG = 1;
-
switch((process_pt)->lc)
-
{
-
case 0:
-
;
- printf(“Hello, world!\n”); /* Initialization code goes here */
-
}
-
-
}
-
PT_YIELD_FLAG = 0;
-
(process_pt)->lc = 0;;
-
return 3;
-
}
- }
process_start
要启动一个进程,必须要用到process_start函数,process_start所干的工作就是- 先把将要执行的进程加入到进程队列process_list的首部,如果这个进程已经在process_list中,就return;
- 接下来就把state设置为PROCESS_STATE_RUNNING并且初始化pt的lc为0(这一步初始化很重要,关系到protothread进程模型的理解);
- 最后通过函数process_post_synch()给进程传递一个PROCESS_EVENT_INIT事件,让其开始执行
为什么process_post_synch()中要把process_current保存起来呢,process_current指向的是一个正在运行的process,当调用call_process执行这个hello_world这个进程时,process_current就会指向当前的process也就是hello_world这个进程,而hello_world这个进程它可能会退出或者正在被挂起等待一个事件,这时process_current = caller 语句正是要恢复先前的那个正在运行的process。
call_process
接下来展开call_process(),这个函数中才是真正的执行了hello_world_process的内容。假如进程process的状态是PROCESS_STATE_RUNNING以及进程中的thread函数不为空的话,就执行这个进程:- 首先把process_current指向p;
- 接着把process的state改为PROCESS_STATE_CALLED;
- 执行hello_world这个进程的body也就是函数p->thread,并将返回值保存在ret中,如果返回值表示退出或者遇到了PROCESS_EVENT_EXIT的时事件后,便执行exit_process()函数,process退出。不然程序就应该在挂起等待事件的状态,那么就继续把p的状态维持为PROCESS_STATE_RUNNING。
exit_process
如果要退出的process就是当前的process,那么就只需要把它从进程列表中清除即可;如果要退出的process不是当前的process,那么当前的process就要给要退出的process传递一个PROCESS_EVENT_EXIT事件让其进程的body退出,然后再将其从进程列表中清除。
总结来说,当Protothread程序运行到PROCESS_WAIT_EVENT()时,判断其运行条件是否满足,若不满足,则阻塞。通过PROCESS_WAIT_EVENT宏展开的程序代码可以得知,Protothread的阻塞其实质就是函数返回,只不过在返回前保存了当前的阻塞位置(也就是lc值),待下一次Protothread被调用时,通过switch语句直接跳到阻塞位置执行,再次判断运行条件是否满足,并执行后续程序或继续阻塞。
Protothread具有以下的特色和优点:
- A design point between events and threads
- Programming primitive: conditional blocking wait
- 3.Single stack
- Sequential flow of control
Programming language helps us: if and while
NOTE:
- 在PROCESS_THREAD内部,auto变量在process挂起时也就是函数返回时是不会被保存的,所以如果需要的话,要把变量设置为static的,这是为了使进程挂起的时候变量的值还在。
- 在PROCESS_THREAD内部不要用switch语句。