Contiki-一个进程的例子

进程调度器

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

开始进程

 1 /**
 2  * Start a process.
 3  *
 4  * \param p A pointer to a process structure.
 5  *
 6  * \param arg An argument pointer that can be passed to the new
 7  * process
 8  *
 9  */
10 CCIF void process_start(struct process *p, const char *arg);
 1 void
 2 process_start(struct process *p, const char *arg)
 3 {
 4   struct process *q;
 5
 6   /* First make sure that we don‘t try to start a process that is
 7      already running. */
 8   for(q = process_list; q != p && q != NULL; q = q->next);
 9
10   /* If we found the process on the process list, we bail out. */
11   if(q == p) {
12     return;
13   }
14   /* Put on the procs list.*/
15   p->next = process_list;
16   process_list = p;
17   p->state = PROCESS_STATE_RUNNING;
18   PT_INIT(&p->pt);
19
20   PRINTF("process: starting ‘%s‘\n", PROCESS_NAME_STRING(p));
21
22   /* Post a synchronous initialization event to the process. */
23   process_post_synch(p, PROCESS_EVENT_INIT, (process_data_t)arg);
24 }

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

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

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

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

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

 1 #include "contiki.h"
 2
 3  PROCESS(example_process, "Example process");
 4  AUTOSTART_PROCESSES(&example_process);
 5
 6  PROCESS_THREAD(example_process, ev, data)
 7  {
 8    PROCESS_BEGIN();
 9
10    while(1) {
11      PROCESS_WAIT_EVENT();
12      printf("Got event number %d\n", ev);
13    }
14
15    PROCESS_END();
16  }  

  上面的代码是一个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()杀死的时候才会被停止运行。

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

 1 static char msg[] = "Data";
 2
 3 static void
 4 example_function(void)
 5 {
 6   /* Start "Example process", and send it a NULL
 7      pointer. */
 8
 9   process_start(&example_process, NULL);
10
11   /* Send the PROCESS_EVENT_MSG event synchronously to
12      "Example process", with a pointer to the message in the
13      array ‘msg‘. */
14   process_post_synch(&example_process,
15                      PROCESS_EVENT_CONTINUE, msg);
16
17   /* Send the PROCESS_EVENT_MSG event asynchronously to
18      "Example process", with a pointer to the message in the
19      array ‘msg‘. */
20   process_post(&example_process,
21                PROCESS_EVENT_CONTINUE, msg);
22
23   /* Poll "Example process". */
24   process_poll(&example_process);
25 }  

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

总结

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

时间: 2024-10-07 02:22:58

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

Contiki教程——进程

概述 Contiki中的代码可以运行在下列两种执行上下文之一:合作式或者抢占式.合作式代码按顺序运行,抢占式代码可以暂停正在运行的合作式代码.Contiki中的进程运行在合作式上下文中,而中断和实时定时器运行在抢占式上下文中. 所有的Contiki程序都被叫做进程.一个进程是Contiki系统中被常规执行的一个代码片段.当系统启动时,或者一个包含进程的模块被加载到系统中时,进程开始运行.当一些事发生时,进程会运行,比如一个定时器到期了,或者有一个外部事件产生. Contiki中的代码可以运行在下

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

本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/8562958 Linux内核中的信号机制--一个简单的例子 Author:ce123(http://blog.csdn.NET/ce123) 信号机制是类UNIX系统中的一种重要的进程间通信手段之一.我们经常使用信号来向一个进程发送一个简短的消息.例如:假设我们启动一个进程通过socket读取远程主机发送过来的网络数据包,此时由于网络因素当前主机还没有收到相应的数据,当前进程被设置

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

转自原文 一个进程间同步和通讯的 C# 框架 threadmsg_demo.zip ~ 41KB    下载 threadmsg_src.zip ~ 65KB    下载 0.背景简介 微软在 .NET 框架中提供了多种实用的线程同步手段,其中包括 monitor 类及 reader-writer锁.但跨进程的同步方法还是非常欠缺.另外,目前也没有方便的线程间及进程间传递消息的方法.例如C/S和SOA,又或者生产者/消费者模式中就常常需要传递消息.为此我编写了一个独立完整的框架,实现了跨线程和跨

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

通过 java.lang.Runtime 类可以方便的调用操作系统命令,或者一个可执行程序,下面的小例子我在windows和linux分别测试过,都通过.基本原理是,首先通过 Runtime.getRuntime() 返回与当前 Java 应用程序相关的运行时对象,然后调用run.exec(cmd)  另启一个进程来执行命令(cmd为要执行的命令). 一.运行一个可执行程序 执行一个.exe的文件,或通过已安装的软件打开一个特定格式的文件,如word.chm或mp3等等. 1. 在window下

实现同一个脚本多次运行,系统中只有一个进程

编写脚本,实现同一个脚本多次运行,系统中只有一个进程 [email protected] scripts]#cat pid.sh #!/bin/sh pidpath=/tmp/a.pid if [ -f "$pidpath" ]   then     kill `cat $pidpath` >/dev/null 2>&1     rm -f $pidpath fi echo $$ >$pidpath sleep 300 测试如下 [email protecte

windows 一个进程可以允许最大的线程数

默认情况下,一个线程的栈要预留1M的内存空间 而一个进程中可用的内存空间只有2G,所以理论上一个进程中最多可以开2048个线程 但是内存当然不可能完全拿来作线程的栈,所以实际数目要比这个值要小. 你也可以通过连接时修改默认栈大小,将其改的比较小,这样就可以多开一些线程. 如将默认栈的大小改成512K,这样理论上最多就可以开4096个线程. 即使物理内存再大,一个进程中可以起的线程总要受到2GB这个内存空间的限制. 比方说你的机器装了64GB物理内存,但每个进程的内存空间还是4GB,其中用户态可用

一个进程的诞生与死亡

执行一个程序,必然就产生一个进程.最直接的程序执行方式就是在shell中以鼠标双击某一个可执行文件图标,执行起来的App进程起始是shell调用CreateProcess激活的. 1.shell调用CreateProcess激活App.exe 2.产生一个进程核心对象,计数值为1 3.系统为此进程建立一个4GB地址空间 4.加载器将必要的代码加载到上述地址空间中,包括App.exe的程序.数据,以及所需要的动态链接函数库DLL.加载器如何知道要加载那些DLLs呢?它们被记录在可执行文件PE文件的

Android Handler的一个简单使用例子

在前面 开启一个线程Thread并用进度条显示进度 这篇文章里,我们用线程实现了这么一个简单的功能,就是点击按钮,加载进度条.但是有没有发现,点击一次之后,再次点击就会没效.我们可是需要每次点击都要显示下一张图片的.永盈会娱乐城 这里就需要引入 Android 的消息机制了,简单来说,就是 Handler.Looper 还有 Message Queue的使用.这里我们用一个简单的例子来说明 Handler 的使用,就是每次点击按钮,给消息队列发送一个数字 5.还是在 PaintingActivi

创建一个进程并调用(.net)

最近有一个项目需求,需要调用一个exe,就上网查询了一下,顺利的完成了工作,感觉虽然简单,但挺有意思,就记录一下. 一,创建一个进程 1,代码视图(控制台程序) 2,代码 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; namespace KillProcess { class Program { static void