当前位置:  编程技术>移动开发
本页文章导读:
    ▪contiki系统分析3:进程分析        contiki系统分析三:进程分析 1. contiki中进程的类型     由图示我们可以看到,contiki中包含两种类型的进程,preemptive(可抢占的)和cooperative(合作的,由于只有两种进程,可以理解为非抢占的).  .........
    ▪ sencha touch 的四中build        sencha touch 的4中build sencha app build 后面一般会有一个参数,不同的参数编译出来的效果不同,具体参照下面: 'production' creates a production build that is normally hosted on a web server and serves multiple c.........
    ▪ 介绍MenuDrawer这个牛x的控件,实现左右出菜单,下上出菜单       介绍MenuDrawer这个牛x的控件,实现左右出菜单,上下出菜单现在很多应用都很潇洒的从左边屏幕手势一划出个左边的隐藏菜单,右边一划出个隐藏菜单,上边一划出个隐藏菜单,下边一划出个.........

[1]contiki系统分析3:进程分析
    来源: 互联网  发布时间: 2014-02-18
contiki系统分析三:进程分析


1. contiki中进程的类型




    由图示我们可以看到,contiki中包含两种类型的进程,preemptive(可抢占的)和cooperative(合作的,由于只有两种进程,可以理解为非抢占的).

  

    preemptive类型:优先级较高.可以在任何时候直接打断cooperative类的进程执行条件. 

   prremptive类型的进程可以由中断(interrupt,完合由硬件产生)或者是实时定时器(real-time timer,指的是contiki系统维护的rtimer)来触发.

   

   cooperative类型的进程:优先级相对较低.可以在contiki系统启动时运行,或者是其它事件触发,这里的事件主要是指timer或者是外部的触发条件.

   cooperative进程执行时,上一个cooerative进程必须执行完.类似于上图的Process B必须等Process A执行完了之后,才能执行.

   cooperativer进程执行的过程中,如果有preemptive类型的进程执行,例如Process B进程.必须要等到preemptive类型的进程执行完之后,Process B进程才能完成它剩下的工作.

   

2. contiki中进程的结构

   contiki中的进程要包括两种类型的数据, 

   进程控制块(PCB, Process Control Block):管理进程的名称,运行时的状态,而且还有进程中的线程的情况,由于是运行时的情况,理所当然在RAM中存储.

  进程中的线程(Process thread):这部分内容放在ROM中


2.1 进程控制块

   进程的状态,名称.  进程中的线程    

  代码中关于进程的定义在core/sys/process.h中

316 struct process {
317   struct process *next;
318 #if PROCESS_CONF_NO_PROCESS_NAMES
319 #define PROCESS_NAME_STRING(process) ""
320 #else
321   const char *name;
322 #define PROCESS_NAME_STRING(process) (process)->name
323 #endif
324   PT_THREAD((* thread)(struct pt *, process_event_t, process_data_t));
325   struct pt pt;
326   unsigned char state, needspoll;
327 };
328 
用户状态下的代码是不能直接操作进程控制块的.只有进程管理相关的函数才可以直接操作.

从process这个结构体的定义上,我们可以看到:

*next 维护contiki进程控制块是一个链表

*name 进程的名字,这个名字主要用在调试上,能够向串口去打印当前的活动进程等其它信息

*thread 函数指针,指向process thread的地址

pt 维护这个进程中的protothread

state 记录进程的状态

needpoll 主要是进程轮询时的状态记录有专门的函数process_poll()对它进行操作.

进程用PROCESS宏进行定义.

308 #define PROCESS(name, strname)              \
309   PROCESS_THREAD(name, ev, data);           \
310   struct process name = { NULL, strname,        \
311                           process_thread_##name }
312 #endif

其中的ev表示process_event_t类型的参数.用在event_data结构体中,用于活动的事件的维护.

再来查看进程控制块中的PT_THREAD宏 ,这个宏与protothread的操作相关.下面会分析protothread的一些信息.

2.2 protothread

protothread没有栈,属于轻量线的线程.主要是用在内存受限的操作系统或者无线传感网络的节点上.

用在事件驱动类型的系统上开一个阻塞的上下文(不包括每个线程中的任务),可以不用复杂的状态机模型进行

顺序流程控制.在C函数中提供有条件的阻塞.

protothread的所有线程都运行在一个上下文中.

protothread可以去调用其它的函数,但是其它的函数不能去调用protothread.

protothread能够在阻塞线程中提供一个线性的代码结构.一般说来,事件驱动的系统会在阻塞调用前

或者是阻塞调用后这两个点上去中断函数的执行.所以对于哪些函数能够阻塞,哪些函数永远也不会阻塞,

代码编写者是完全清楚的.

但是使用protothread也要特别小心,它没有完整的线程上下文.也就是局部变量的值没有在栈上保存.

千万不要在protothread中随便使用局部变量.除非你知道这个局部变量的作用域.

下面以contiki中的hello world的例子来分析一下protothread的实现及调用.

代码在examples/hello-world/hello-world.c中

 40 #include "contiki.h"
 41 
 42 #include <stdio.h> /* For printf() */
 43 /*---------------------------------------*/
 44 PROCESS(hello_world_process, "Hello world process");
 45 AUTOSTART_PROCESSES(&hello_world_process);
 46 /*---------------------------------------*/
 47 PROCESS_THREAD(hello_world_process, ev, data)
 48 {
 49   PROCESS_BEGIN();
 50 
 51   printf("Hello, world\n");
 52   
 53   PROCESS_END();
 54 }

如果手工分析宏代码,会得到以下结果:

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data);
struct process hello_world_process = { 
    NULL, 
    "Hello world process",
    process_thread_hello_world_process
}

struct process * const autostart_processes[] = {&hello_world_process, NULL}

static char process_thread_hello_world_process(struct pt *process_pt, process_event_t ev, process_data_t data)
{
    char PT_YIELD_FLAG = 1;  

    if (PT_YIELD_FLAG) {;} 

    switch(process_pt->lc) 
    {   
        case 0:
            printf("Hello, world\n");
    }   

    PT_YIELD_FLAG = 0;  
    process_pt->lc=0;

    return PT_ENDED; 
}
当然,如果图省事.可以用gcc的预编译参数.得到结果

进入example下的hello-world目录,预编译的命令:

[ycwang@ycwang:hello-world]$ gcc -E -DCONTIKI=1 -DCONTIKI_TARGET_NATIVE=1 -Wall -g -I/usr/local/include  -O  -I. -I../../platform/native/. -I../../platform/native/dev -I../../cpu/native/. -I../../cpu/native/net -I../../core/dev -I../../core/lib -I../../core/net -I../../core/net/mac -I../../core/net/rime -I../../core/net/rpl -I../../core/sys -I../../core/cfs -I../../core/ctk -I../../core/lib/ctk -I../../core/loader -I../../core/. -I../../platform/native/ -DAUTOSTART_ENABLE -c hello-world.c -o hello-world.co
然后打开 -o 后面的文件名.


可以看出,contiki中的process是基于protothread的.至少有一个protothread.

struct pt是用来跳转或者是返回到当前的thread的.pt->lc正是protothread运行的核心.

关于LC的几个宏的定义在文件core/sys/lc-switch.h中

#define LC_INIT(s) s = 0;

#define LC_RESUME(s) switch(s) { case 0:

#define LC_SET(s) s = __LINE__; case __LINE__:

#define LC_END(s) }
由于 这几个宏展开的话,就成了switch case的选择语句.一定不能出现LC_SET混用在其它switch语句中的情况.

由于LC_SET直接取的是代码所在的行数.编译器会找到对应的代码段的地址.那么,通过变化__LINE__,就可以切换一个进程中的不同的PT.这是PT线程没有栈的根本原因.

LC相关的这几个宏不能直接在代码中调用.一般是通过PT或者PROCESS的宏来调用.

公共接口是

PROCESS_BEGIN() : 初始化定义PT PROCESS_END() : 用在彻底结束PT之前 PROCESS_EXIT() : 完全退出PT PROCESS_WAIT_EVENT() : 件等待,两种事件,同步或异步事件 PROCESS_WAIT_EVENT_UNTIL() : 当条件触发时,运行PT,等待条件 PROCESS_YIELD() : 等待触发条件,与PROCESS_WAIT_EVENT()等价 PROCESS_WAIT_UNTIL() : 等待触发条件,也许下可能让出PT PROCESS_PAUSE() : 临时出让PT.

关于PROCESS相关的几个宏的例子在contiki的源码里倒处都是,例如platform/esb/apps/pinger.c


2.3事件

contiki中有两种事件.异步事件,同步事件.


2.3.1异步事件



异步事件主要存放在事件队列中,然后去循环执行.用process_post()把进程加入队列中.


2.3.2 同步事件



立即执行.实现函数process_pose_synch().

2.3.3 轮询方式

通过process_poll()函数,然后直接执行被poll的进程.轮询是从中断中让一个进程执行的一种方法.

2.3.4 事件标识符

Event Identifier是用来标识事件的,在contiki中用一个8位的数来区分.根据标识符的不同类型做不同的处理,其中用户定义的进程的范围在0~127之间.

其它的进程是contiki的内核去定义的.定义的结果如下

 #define PROCESS_EVENT_NONE            128
 #define PROCESS_EVENT_INIT            129
 #define PROCESS_EVENT_POLL            130
 #define PROCESS_EVENT_EXIT            131
 #define PROCESS_EVENT_CONTINUE        133
 #define PROCESS_EVENT_MSG             134
 #define PROCESS_EVENT_EXITED          135
 #define PROCESS_EVENT_TIMER           136

PROCESS_EVENT_NONE : 用来隔离用户与内核定义的描述符,没有其它作用. PROCESS_EVENT_INIT : 当初始化的时候,把事件发送到一个新的进程,这种类型只是用于进程初始化时把进程的状态切换到running.可以参考do_event()的实现.用于非广播方式向特定的进程发送信息时,才做切换处理.如果是用广播方式发送,就会对每一个进程做do_poll()操作. PROCESS_EVENT_POLL : 事件的轮询标记,主要用于do_poll()的实现. PROCESS_EVENT_EXIT : 用在exit_process()中,用来同步通知contiki的服务,这个进程即将结束,需要释放或解除与这个进程相关的状态. PROCESS_EVENT_CONTINUE :由内核发给进程,等待PROCESS_YIELD() 的状态.PROCESS_PAUSE()中用这个标识才做短暂的暂停,等到标识符所表示的状态时,继续执行. PROCESS_EVENT_MSG :主要用在IP协议栈中,但是,也能够用在进程间通信. PROCESS_EVENT_EXITED : 用在exit_process()中,用来向非进程P的其它所有进程广播,进程P将退出.但是PROCESS_EVENT_EXIT是通知进程P中的线程退出.然后在链表中删除进程. PROCESS_EVENT_TIMER :当事件时钟(etimer)失效时,发消息给进程

2.4 进程调度器

进程调度器的目标就是为了使得每个进程在属于它自己的时间段内运行.进程调度器调用执行进程中的线程的函数来完成调度.contiki中的所有进程调用无外乎下面的几种方式.1.响应了进程中的特定的事件. 2. 轮循中请求进程.3. 进程调度器把事件标识符传给了要调用的进程.通过进程描述符,对应的指针也传到了进程中.指针为NULL的情况表示事件还没有传递数据.但是如果是通过轮循方式请求进程,也不会传递数据.

2.4.1 进程开始

contiki中用process_start()函数来开始一个进程.

1.检查这个进程是否已经在运行(从运行队列中查找是否有这个进程),如果运行,则退出.

2.如果进程没有在运行队列中,则把进程加入运行队列,并全用PT_INIT来初始化进程,并且赋给PROCESS_EVENT_INIT的标识符.如果有数据的话,把指针传到进程中.用INIT类型的标识符,是为了让在进程实际运行前,有一部分代码做初始化工作.


2.4.2 退出并杀死进程

进程退出有两种方式,

1.自己退出,一般是执行到PROCESS_EXIT()所在的宏的位置,或者是有PROCESS_END()状态的位置.进程将结束.

2.被另外一个进程杀死.调用process_exit()函数.

当进程退出时,不管这个进程是怎么退出的.contiki都会发一个消息给其它还没有退出的进程.这样便于释放由退出的进程占用的资源.比如在IP协议栈中,如果一个进程发起来了一个连接,但是这个进程已经退出的话,那么协议栈就会中断连接.从而释放资源.

最后contiki系统再把进程从队列中移除.


2.4.3 自动启动的进程

这种类型的进程也分两种启动方式.

1. 在contiki开始启动时,启动进程

2. 在一个模块开始装载时,自动启动进程

自启动的状态机可以反应出有哪些模块启动了.如果模块要卸栽的话,也可以随时释放内存.


3 示例分析

借用一个最简单的例子hello world来反映进程的实际运行情况。

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

关于PROCESS和PROCESS_THREAD宏的展开,上面已经分析过了。AUTOSTART_PROCESSES这个宏主要是用来在contiki启动时,就启动进程。还有种情况是当装载模块时,开始运行。所以要传入example_process的地址进来。

PROCESS_WAIT_EVENT()主要是等待contiki的内核调度完成。真正执行这个进程上的代码。

关键的两个参数。

ev是指事件的参数

data是指传递数据的指针


4 总结


进和是contiki中比较重要应用。进程中包括进程控制块和线程两部分。进程控制块用来提供进程运行时的信息,而进程中的线程包括进程的代码。线程也就是轻量级的protothread。

进程运行分可抢占的,和不可抢占的。其中,可抢占的进程只有一种情况process_poll().


    
[2] sencha touch 的四中build
    来源: 互联网  发布时间: 2014-02-18
sencha touch 的4中build


sencha app build 后面一般会有一个参数,不同的参数编译出来的效果不同,具体参照下面:



  • 'testing' is meant for QA prior to production. All JavaScript and CSS source Files are bundled, but not minified, which makes it easier for debugging if needed
用于测试,只是把所有的js打包成一个app.js
  • 'package' creates a self-contained, re-distributable production build that normally runs from local file system without the need for a web server
只打包了关联的js

  • 'production' creates a production build that is normally hosted on a web server and serves multiple clients (devices). The build is offline-capable using HTML 5 application cache, and has built-in over-the-air delta updating feature
自动生成了离线缓存

  • 'native' first generates a 'package' build, then packages it as a native application, ready to be deployed to native platforms
  • 这种方式生成My Application.app,用于ios产品封装


    
[3] 介绍MenuDrawer这个牛x的控件,实现左右出菜单,下上出菜单
    来源: 互联网  发布时间: 2014-02-18
介绍MenuDrawer这个牛x的控件,实现左右出菜单,上下出菜单

现在很多应用都很潇洒的从左边屏幕手势一划出个左边的隐藏菜单,右边一划出个隐藏菜单,上边一划出个隐藏菜单,下边一划出个隐藏菜单。或者像android的API16左右的激活列表项的功能。很多人肯定都很着迷。呵呵,其实实现很简单的,大部分的人都是使用我说的这个控件改的,不是说国内的人水平低,而是国外真是有牛人啊。

好了无图不真相,大家可以看看截图。如果想自己玩玩,或者要代码啥的,直接下去吧。

https://github.com/licong/android-menudrawer

下面这个图是很多人梦寐以求的激活列表项的功能:

下面这个图是很多人梦寐以求的左出菜单的功能:



下面这个图是很多人梦寐以求的下出菜单的功能:





下面这个图是很多人梦寐以求的右出菜单的功能:










    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3