进程调度器

  进程调度器的作用是调用进程。进程调度器通过调用实现进程线程的函数来调用进程。Contiki中所有的进程被设计为响应传递到进程中的事件,或者相应进程请求的轮询。进程调度器在调度进程的时候会将事件标识符和一个不透明指针传递到进程中,该指针由进程调用者提供,可以设置为NULL(该事件不需要传递数据)。当进程轮询时,不会传递数据。

开始进程

 /**
* Start a process.
*
* \param p A pointer to a process structure.
*
* \param arg An argument pointer that can be passed to the new
* process
*
*/
CCIF void process_start(struct process *p, const char *arg);
 void
process_start(struct process *p, const char *arg)
{
struct process *q; /* First make sure that we don't try to start a process that is
already running. */
for(q = process_list; q != p && q != NULL; q = q->next); /* If we found the process on the process list, we bail out. */
if(q == p) {
return;
}
/* Put on the procs list.*/
p->next = process_list;
process_list = p;
p->state = PROCESS_STATE_RUNNING;
PT_INIT(&p->pt); PRINTF("process: starting '%s'\n", PROCESS_NAME_STRING(p)); /* Post a synchronous initialization event to the process. */
process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
}

  process_start()开始一个进程。该函数的目的是设置进程控制块,将进程加入到内核有效进程链表中,然后调用进程线程中的初始化代码。最后给该进程发送一个同步的初始化事件。process_start()被调用后,该进程就开始运行了。

  process_start()函数先做一个明智的检查,检查是否该进程已经存在进程链表中。如果是,表明该进程已经被运行了,process_start()函数直接返回。在确认该进程没有开始运行后,内核将该进程加入到链表中,并设置进程控制块。进程的状态被设置为PROCESS_STATE_RUNNING,进程的线程被PT_INIT()初始化。最后,内核为进程发送给一个同步事件PROCESS_EVENT_INIT,且传递一个不透明指针给进程,该指针是由调用process_start()的进程传入的,用于传递给要运行的进程一些信息。不过,这个指针一般都设为NULL。当进程接收到它的第一个事件PROCESS_EVENT_INIT,进程将执行该进程线程的第一部分。通常,这部分包含进程开始时即将运行的初始化代码。

退出进程和杀死进程

  进程退出有两种方法:进程自动退出和被其它进程杀死。调用函数process_exit()或者当进程线程执行到PROCESS_END()语句时,进程将退出。

  进程可以调用函数process_exit()杀死另一个进程。

  当一个进程退出(无论是主动退出还是被动退出),Contiki内核会发送给一个事件通知其它进程,这可以让其它进程释放退出进程所占有的资源。事件PROCESS_EVENT_EXITED将会被以同步事件的方式发送到其它所有进程。

  当一个被另一个金曾杀死时,被杀的进程将会接收到同步事件PROCESS_EVENT_EXIT,该事件通知将要被杀死的进程和能够释放已分配资源的进程,或者其它将要退出的进程。

  在Contiki内核发送事件通知将要退出的进程后,将从进程链表中删除该进程。

自启动进程

  Contiki提供了一个机制,在系统启动时,或者包含进程的模块被加载时,自动运行进程。该机制由自启动模块实现。该机制能够让模块开发者告知系统该模块中包含什么进程。当模块从内存中移除时,也能让系统做相应的处理。

  自启动进程保存在一个链表中,自启动模块利用该链表实现自动运行进程。进程启动的顺序与它在链表中的顺序一致。

  自启动进程有两种时机:系统启动时和模块被加载时。所有需要在系统启动时自启动的进程必须被包含在一个单一的系统级的链表中。这个自启动链表由用户提供,且一般在一个用户模块中。当这个模块被用作可加载模块时,链表能够让系统知道模块被加载时需要运行什么进程。

  当加载一个模块时,模块加载器将查找自启动进程链表,并在模块被加载到内存后启动链表中的进程。当模块将要被卸载时,模块加载器利用该链表杀死在模块加载时启动的进程。

一个接收事件并打印其数字的进程的例子

 #include "contiki.h"  

  PROCESS(example_process, "Example process");
AUTOSTART_PROCESSES(&example_process); PROCESS_THREAD(example_process, ev, data)
{
PROCESS_BEGIN(); while() {
PROCESS_WAIT_EVENT();
printf("Got event number %d\n", ev);
} PROCESS_END();
}

  上面的代码是一个Contiki完整的进程。该进程被申明、定义和自动运行。

  第三行,我们定义了进程控制块。进程控制块定义了进程控制块的名字example_process和文本的、用户可读的进程名字Example process。在定义了进程控制块后,我们可以在其它表达式中使用该变量名。

  第四行,语句AUTOSTART_PROCESSES()告诉Contiki在系统启动时自动启动进程example_process。自启动链表由指向进程控制块的指针组成,所以需要在变量example_process前加&取地址符。

  第六行,我们定义了进程线程。它包含了进程的变量名example_process和传递事件的变量ev及数据data。

  第八行,我们使用了PROCESS_BEGIN()定义了一个进程的开始。该定义标志进程线程的开始。在进程每次被调度运行的时候,该申明语句上面的代码都会运行。在大多数情形下,你不需要在PROCESS_BEGIN()之上放任何代码。

  第十行,开始进程的主循环。Contiki进程不能包含永不结束的死循环。但是在上面代码中,这样的死循环是安全的,因为进程将会等待时间。当一个Contiki进程在等待事件时,它会将控制器返回给Contiki内核。在该进程等待期间,内核将会为其它进程提供服务。

  第十一行,进程等待事件的发生。表达式PROCESS_WAIT_EVENT()将返回控制权给Contiki内核,并等待内核传递事件到该进程。当Contiki内核传递事件给该进程后,PROCESS_WAIT_EVENT()后面的代码将被执行。在进程被唤醒后,将执行第十二行的打印语句。这一行的作用是打印进程接收到的事件编号。如果同时传入 了一个指针,该指针变量就是data(?)。

  第十五行,PROCESS_END()标识进程的结束。每个Contiki进程必须包含PROCESS_BEGIN()和PROCESS_END()。当执行到PROCESS_END()时,该进程自动退出,并从内核中的进程链表中移除。不过,由于存在死循环,永远不会执行到PROCESS_END()。只有系统被关掉、或者该进程被process_exit()杀死的时候才会被停止运行。

一个启动进程并发送事件的函数

 static char msg[] = "Data";  

 static void
example_function(void)
{
/* Start "Example process", and send it a NULL
pointer. */ process_start(&example_process, NULL); /* Send the PROCESS_EVENT_MSG event synchronously to
"Example process", with a pointer to the message in the
array 'msg'. */
process_post_synch(&example_process,
PROCESS_EVENT_CONTINUE, msg); /* Send the PROCESS_EVENT_MSG event asynchronously to
"Example process", with a pointer to the message in the
array 'msg'. */
process_post(&example_process,
PROCESS_EVENT_CONTINUE, msg); /* Poll "Example process". */
process_poll(&example_process);
}

  两个进程间通过事件完成交互。上面的例子中的函数启动了一个进程,并向它发送一个同步事件和轮询请求。

总结

  进程通过发送事件实现与其它进程通信。

摘录自:http://blog.csdn.net/tidyjiang/article/details/51378589

Contiki-一个进程的例子的更多相关文章

  1. 让powershell同时只能运行一个脚本(进程互斥例子)

    powershell,mutex,互斥,进程互斥,脚本互斥 powershell脚本互斥例子,在powershell类别文章中,声明原创唯一. powershell 传教士 原创文章 2016-07- ...

  2. Erlang 进程被抢占的条件——一个进程长时霸占调度器的极端示例

    最近研究 binary 的实现和各种操作对应的 beam 虚拟机汇编指令,发现有一些指令序列是不可重入的,比如说有的指令构造一个上下文(也就是某种全局状态),然后下一条指令会对这个上下文做操作(具体的 ...

  3. JAVA调用系统命令或可执行程序--返回一个Runtime运行时对象,然后启动另外一个进程来执行命令

    通过 java.lang.Runtime 类可以方便的调用操作系统命令,或者一个可执行程序,下面的小例子我在windows和linux分别测试过,都通过.基本原理是,首先通过 Runtime.getR ...

  4. 一个UWSGI的例子

    摘要:uwsgi执行顺序:启动master进程,执行python脚本的公共代码(import同一层).然后生成worker进程,uwsgi.post_fork_hook=init_functions, ...

  5. 网络编程基础【day10】:我是一个进程(三)

    本节内容 1.引子 2.进程的诞生 3.线程 4.争吵 一.引子 我听说我的祖先们生活在专用计算机里, 一生只帮助人类做一件事情,比说微积分运算 了.人口统计了 .生成密码.甚至通过织布机印花 !   ...

  6. 一个进程间同步和通讯的 C# 框架

    转自原文 一个进程间同步和通讯的 C# 框架 threadmsg_demo.zip ~ 41KB    下载 threadmsg_src.zip ~ 65KB    下载 0.背景简介 微软在 .NE ...

  7. Linux内核中的信号机制--一个简单的例子【转】

    本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/8562958 Linux内核中的信号机制--一个简单的例子 Author:ce123 ...

  8. Qt 进程和线程之一:运行一个进程和进程间通信

    Qt提供了对进程和线程的支持.本节讲述了怎样在Qt应用程序中启动一个进程,以及几种常用的进程间通信方法.如果对进程和线程的概念不是很了解,可以看我的另一篇博客:[多进程和多线程的概念. 设计应用程序时 ...

  9. C# 最基本的涉及模式(单例模式) C#种死锁:事务(进程 ID 112)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务,解决方案: C#关闭应用程序时如何关闭子线程 C#中 ThreadStart和ParameterizedThreadStart区别

    C# 最基本的涉及模式(单例模式) //密封,保证不能继承 public sealed class Xiaohouye    { //私有的构造函数,保证外部不能实例化        private  ...

随机推荐

  1. 国内外从事CV相关的企业

    提示:本文为笔者原创,转载请注明出处:blog.csdn.net/carson2005 经常碰到朋友问我国内从事计算机视觉(CV)领域的公司的发展情况,产品情况,甚至找工作等问题,这里,我给出自己收集 ...

  2. Oracle Partition By 的使用

    1.概述 Parttion by 关键字是Oracle中分析性函数的一部分,它和聚合函数不同的地方在于它能够返回一个分组中的多条记录,儿聚合函数一般只有一条反映统计值的结果. 2.使用方式 场景:查询 ...

  3. 转 苹果企业级帐号进行ipa打包,分发,下载等流程

    1,企业帐号介绍(1)使用企业开发帐号,我们可以发布一个 ipa 放到网上,所有人(包括越狱及非越狱设备)都可以直接通过链接下载安装,而不需要通过 AppStore 下载,也不需要安装任何证书.(2) ...

  4. VTID配置

    车牌过滤: [FilterByHour] text=${Channel},${Plate.type},${Frame.Time(%H)} all=true rule01= ^$,^$,^[]$ =&g ...

  5. jQuery基本操作

    jQuery简介 jQuery是一个兼容多浏览器的javascript库,极大地简化了 JavaScript 编程,核心理念是write less,do more(写得更少,做得更多),对javasc ...

  6. CountDownLatch和CyclicBarrier 举例详解

    有时候会有这样的需求,多个线程同时工作,然后其中几个可以随意并发执行,但有一个线程需要等其他线程工作结束后,才能开始.举个例子,开启多个线程分块下载一个大文件,每个线程只下载固定的一截,最后由另外一个 ...

  7. DP专题训练之HDU 1231 最大连续子序列

    Description 给定K个整数的序列{ N1, N2, ..., NK },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j < ...

  8. 《编写可维护的JavaScript》——JavaScript编码规范(七)

    UI层的松耦合 在web开发中,用户界面(UI)是由三个彼此隔离又相互作用的层定义的. HTML用来定义页面的数据和语义. CSS用来给页面添加样式,创建视觉特征. JavaScript用来给页面添加 ...

  9. 【转】Hibernate 常见异常

    转载地址:http://smartan.iteye.com/blog/1542137 Hibernate 常见异常net.sf.hibernate.MappingException        当出 ...

  10. linux下打开、关闭tomcat,实时查看tomcat运行日志

    启动:一般是执行sh tomcat/bin/startup.sh 停止:一般是执行sh tomcat/bin/shutdown.sh脚本命令 查看:执行ps -ef |grep tomcat 输出如下 ...