實驗15-基于IPv6模塊的進程間交互的實驗講解_第1頁
實驗15-基于IPv6模塊的進程間交互的實驗講解_第2頁
實驗15-基于IPv6模塊的進程間交互的實驗講解_第3頁
實驗15-基于IPv6模塊的進程間交互的實驗講解_第4頁
實驗15-基于IPv6模塊的進程間交互的實驗講解_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

精選優(yōu)質(zhì)文檔-----傾情為你奉上精選優(yōu)質(zhì)文檔-----傾情為你奉上專心---專注---專業(yè)專心---專注---專業(yè)精選優(yōu)質(zhì)文檔-----傾情為你奉上專心---專注---專業(yè)實驗題目:實驗15—基于IPv6模塊的進程間交互的實驗實驗時間:2016.1.4實驗目的:了解Cygwin開發(fā)環(huán)境及Contiki系統(tǒng)相關(guān)內(nèi)容。了解Contiki系統(tǒng)進程間交互的理論掌握IPv6模塊的編程及下載使用方法。實驗原理及程序分析:1、Contiki中事件驅(qū)動和protothread機制Contiki的兩個主要機制:事件驅(qū)動和protothread機制,前者是為了降低功耗,后者是為了節(jié)省內(nèi)存。事件驅(qū)動嵌入式系統(tǒng)常常被設計成響應周圍環(huán)境的變化,而這些變化可以看成一個個事件。事件來了,操作系統(tǒng)處理之,沒有事件到來,就跑去休眠了(降低功耗),這就是所謂的事件驅(qū)動,類似于中斷。事件結(jié)構(gòu)體事件也是Contiki重要的數(shù)據(jù)結(jié)構(gòu),其定義如下:structevent_data{process_event_tev;process_data_tdata;structprocess*p;};typedefunsignedcharprocess_event_t;typedefvoid*process_data_t;各成員變量含義如下:ev-----標識所產(chǎn)生事件data---保存事件產(chǎn)生時獲得的相關(guān)信息,即事件產(chǎn)生后可以給進程傳遞的數(shù)據(jù)p------指向監(jiān)聽該事件的進程事件分類事件可以被分為三類:時鐘事件(timerevents)、外部事件、內(nèi)部事件。那么,Contiki核心數(shù)據(jù)結(jié)構(gòu)就只有進程和事件了,把etimer理解成一種特殊的事件。事件隊列Contiki用環(huán)形隊列組織所有事件(用數(shù)組存儲),如下:staticstructevent_dataevents[PROCESS_CONF_NUMEVENTS];圖示事件隊列如下:系統(tǒng)定義的事件系統(tǒng)定義了10個事件,源碼和注釋如下:#ifndefPROCESS_CONF_NUMEVENTS#definePROCESS_CONF_NUMEVENTS32#endif#definePROCESS_EVENT_NONE0x80//函數(shù)dhcpc_request調(diào)用handle_dhcp(PROCESS_EVENT_NONE,NULL)#definePROCESS_EVENT_INIT0x81//啟動一個進程process_start,通過傳遞該事件#definePROCESS_EVENT_POLL0x82//在PROCESS_THREAD(etimer_process,ev,data)使用到#definePROCESS_EVENT_EXIT0x83//進程退出,傳遞該事件給進程主體函數(shù)thread#definePROCESS_EVENT_SERVICE_REMOVED0x84#definePROCESS_EVENT_CONTINUE0x85//PROCESS_PAUSE宏用到這個事件#definePROCESS_EVENT_MSG0x86#definePROCESS_EVENT_EXITED0x87//進程退出,傳遞該事件給其他進程#definePROCESS_EVENT_TIMER0x88//etimer到期時,傳遞該事件#definePROCESS_EVENT_COM0x89#definePROCESS_EVENT_MAX0x8a/*進程初始化時,讓lastevent=PROCESS_EVENT_MAX,即新產(chǎn)生的事件從0x8b開始,函數(shù)process_alloc_event用于分配一個新的事件*/注:PROCESS_EVENT_EXIT與PROCESS_EVENT_EXITED區(qū)別事件PROCESS_EVENT_EXIT用于傳遞給進程的主體函數(shù)thread,如在exit_process函數(shù)中的p->thread(&p->pt,PROCESS_EVENT_EXIT,NULL)。而PROCESS_EVENT_EXITED用于傳遞給進程,如call_process(q,PROCESS_EVENT_EXITED,(process_data_t)p)。(助記:EXITED是完成式,發(fā)給進程,讓整個進程結(jié)束。而g一般式EXIT,發(fā)給進程主體thread,只是使其退出thread)一個特殊事件如果事件結(jié)構(gòu)體event_data的成員變量p指向PROCESS_BROADCAST,則該事件是一個廣播事件。在do_event函數(shù)中,若事件的p指向的是PROCESS_BROADCAST,則讓進程鏈表process_list所有進程投入運行。部分源碼如下:#definePROCESS_BROADCASTNULL//廣播進程/*保存待處理事件的成員變量*/ev=events[fevent].ev;data=events[fevent].data;receiver=events[fevent].p;if(receiver==PROCESS_BROADCAST){for(p=process_list;p!=NULL;p=p->next){if(poll_requested){do_poll();}call_process(p,ev,data);}}protothread機制概述protothread是contiki的進程控制模型,是contiki關(guān)于進程的精華知識。傳統(tǒng)的操作系統(tǒng)使用棧保存進程上下文,每個進程需要一個棧,這對于內(nèi)存極度受限的傳感器設備將難以忍受。protothread機制恰解決了這個問題,通過保存進程被阻塞處的行數(shù)(進程結(jié)構(gòu)體的一個變量,unsigedshort類型,只需兩個字節(jié)),從而實現(xiàn)進程切換,當該進程下一次被調(diào)度時,通過switch(__LINE__)跳轉(zhuǎn)到剛才保存的點,恢復執(zhí)行。整個Contiki只用一個棧,當進程切換時清空,大大節(jié)省內(nèi)存。特點protothread(-Lightweight,StacklessThreadsinC)最大特點就是輕量級,每個protothread不需要自己的堆棧,所有的protothread使用同一個堆棧,而保存程序斷點用兩個字節(jié)保存被中斷的行數(shù)即可。具體特點如下:VerysmallRAMoverhead-onlytwobytesperprotothreadandnoextrastacksHighlyportable-theprotothreadslibraryis100%pureCandnoarchitecturespecificassemblycodeCanbeusedwithorwithoutanOSProvidesblockingwaitwithoutfullmulti-threadingorstack-switchingFreelyavailableunderaBSD-likeopensourcelicenseprotothread機制很早就有了,ContikiOS只要運用這種機制,protothread機制還可以用于以下情形:MemoryconstrainedsystemsEvent-drivenprotocolstacksSmallembeddedsystemsSensornetworknodesPortableCapplications編程提示謹慎使用局部變量。當進程切換時,因protothread沒有保存堆棧上下文(只使用兩個字節(jié)保存被中斷的行號),故局部變量得不到保存。這就要求使用局部變量要特別小心,一個好的解決方法,使用局部靜態(tài)變量(加static修飾符),如此,該變量在整個生命周期都存在。調(diào)度Aprotothreadisdrivenbyrepeatedcallstothefunctioninwhichtheprotothreadisrunning.Eachtimethefunctioniscalled,theprotothreadwillrununtilitblocksorexits.Ttothread模型之代碼分析當?shù)谝淮螆?zhí)行這個函數(shù)時,便會執(zhí)行PT_YIELD_FLAG=1。因為(process_pt)->lc被初始化為0,所以就直接輸出helloworld。當進入到while循環(huán)時:while(1){/*Waitforanevent.*///PROCESS_WAIT_EVENT();do{PT_YIELD_FLAG=0;(process_pt)->lc=__LINE__;case__LINE__:;if(PT_YIELD_FLAG==0){return1;}}while(0);/*Gotthetimer'sevent~*/}當這個process收到一個事件再次被執(zhí)行的時候,首先會進行初始化,讓PT_YIELD_FLAG=1,接著進入switch語句,因為(process_pt)->lc已經(jīng)被保存,所以這次process直接跳到了上次的執(zhí)行結(jié)束的地方重新開始執(zhí)行了,因為PT_YIELD_FLAG已經(jīng)是1了,所以就不會return了。就會繼續(xù)執(zhí)行上次執(zhí)行的代碼。所以(process_pt)->lc相當于保持了現(xiàn)場,下次函數(shù)再運行的時候就可以通過switch語句迅速找到執(zhí)行代碼語句的入口,恢復現(xiàn)場,繼續(xù)執(zhí)行。執(zhí)行完畢后,接著while循環(huán),return后,再等待事件,一直循環(huán)。2、Contiki中進程概念進程結(jié)構(gòu)體進程結(jié)構(gòu)體源碼如下:structprocess{structprocess*next;//指向下一個進程/******進程名稱***********/#ifPROCESS_CONF_NO_PROCESS_NAMES#definePROCESS_NAME_STRING(process)""#elseconstchar*name;#definePROCESS_NAME_STRING(process)(process)->name#endifPT_THREAD((*thread)(structpt*,process_event_t,process_data_t));//structptpt;//unsignedcharstate;//unsignedcharneedspoll;//};進程名稱運用C語言預編譯指令,可以配置進程名稱,宏P(guān)ROCESS_NAME_STRING(process)用于返回進程process名稱,若系統(tǒng)無配置進程名稱,則返回空字符串。在以后討論中,均假設配有進程名稱。PT_THREAD宏P(guān)T_THREAD宏定義如下:#definePT_THREAD(name_args)charname_args故“PT_THREAD((*thread)(structpt*,process_event_t,process_Data_t));”語句展開如下:char(*thread)(structpt*,process_event_t,process_data_t);聲明一個函數(shù)指針thread,指向的是一個含有3個參數(shù),返回值為char類型的函數(shù)。這是進程的主體,當進程執(zhí)行時,主要是執(zhí)行這個函數(shù)的內(nèi)容。另,聲明一個進程包含在宏P(guān)ROCESS(name,strname)里,通過宏AUTOSTART_PROCESSES(...)將進程加入自啟動數(shù)組中。Ptpt結(jié)構(gòu)體一步步展開如下:structpt{lc_tlc;};typedefunsignedshortlc_t;如此,可以把structptpt直接理解成unsignedshortlc,以后如無特殊說明,pt就直接理解成lc。lc(localcontinuations)用于保存程序被中斷的行數(shù)(只需兩個字節(jié),這恰是protothread輕量級的集中體現(xiàn)),被中斷的地方,保存行數(shù)(s=__LINE__)接著是語句case__LINE__。當該進程再次被調(diào)度時,從PROCESS_BEGIN()開始執(zhí)行,而該宏展開含有這條語句switch(process_pt->pt),從而跳到上一次被中斷的地方(即case__LINE__),繼續(xù)執(zhí)行。進程狀態(tài)進程共3個狀態(tài),宏定義如下:#definePROCESS_STATE_NONE0/*類似于Linux系統(tǒng)的僵尸狀態(tài),進程已退出,只是還沒從進程鏈表刪除*/#definePROCESS_STATE_RUNNING1/*進程正在執(zhí)行*/#definePROCESS_STATE_CALLED2/*實際上是返回,并保存lc值*/Needspoll簡而言之,needspoll為1的進程有更高的優(yōu)先級。具體表現(xiàn)為,當系統(tǒng)調(diào)用process_run()函數(shù)時,把所有needspoll標志為1的進程投入運行,而后才從事件隊列取出下一個事件傳遞給相應的監(jiān)聽進程。與needspoll相關(guān)的另一個變量poll_requested,用于標識系統(tǒng)是否存在高優(yōu)先級進程,即標記系統(tǒng)是否有進程的needspoll為1。staticvolatileunsignedcharpoll_requested;進程鏈表基于上述分析,將代碼展開或簡化,得到如下進程鏈表process_list:創(chuàng)建進程及啟動進程創(chuàng)建進程主要由PROCESS宏(聲明進程)和PROCESS_THREAD宏(定義進程執(zhí)行主體)完成,詳情前一章helloword分析,啟動進程由process_start函數(shù)完成,總是把進程加入到進程鏈表的頭部。3、進程、事件、etimer三者關(guān)系進程process、事件event_data、etimer都是Contiki的核心數(shù)據(jù)結(jié)構(gòu),理清這三者關(guān)系,將有助于對系統(tǒng)的理解。事件與etimer關(guān)系事件即可以分為同步事件、異步事件,也可以分為定時器事件、內(nèi)部事件、外部事件。而etimer屬于定時器事件的一種,可以理解成Contiki系統(tǒng)把etimer單列出來,方便管理(由etimer_process系統(tǒng)進程管理)。當etimer_process執(zhí)行時,會遍歷etimer鏈表,檢查etimer是否有到期的,凡有timer到期就把事件PROCESS_EVENT_TIMER加入到事件隊列中,并將該etimer成員變量p指PROCESS_NONE。在這里,PROCESS_NONE用于標識該etimer是否到期,函數(shù)etimer_expired會根據(jù)etimer的p是否指向PROCESS_NONE來判斷該etimer是否到期。進程與etimer關(guān)系etimer與process還不是一一對應的關(guān)系,一個etimer必定綁定一個process,但process不一定非得綁定etimer。etimer只是一種特殊事件罷了。進程與事件關(guān)系當有事件傳遞給進程時,就新建一個事件加入事件隊列,并綁定該進程,所以一個進程可以對應于多個事件(即事件隊列有多個事件跟同一個進程綁定),而一個事件可以廣播給所有進程,即該事件成員變量p指向空。當調(diào)用do_event函數(shù)時,將進程鏈表所有進程投入運行。4、源碼分析源碼//filename:process-interact.c進程間交互#include"contiki.h"#include<stdio.h>/*Forprintf()*/staticprocess_event_tevent_data_ready;/*聲明兩個進程*/PROCESS(print_hello_process,"Hello");PROCESS(print_world_process,"world");AUTOSTART_PROCESSES(&print_hello_process,&print_world_process);//讓該兩進程自啟動/*定義進程print_hello_process*/PROCESS_THREAD(print_hello_process,ev,data){PROCESS_BEGIN();staticstructetimertimer;etimer_set(&timer,CLOCK_CONF_SECOND/10);//#defineCLOCK_CONF_SECOND10將timer的interval設為1printf("***printhelloprocessstart***\n");event_data_ready=process_alloc_event();//returnlastevent++;新建一個事件,事實上是用一組unsignedchar值來標識不同事件while(1){PROCESS_WAIT_EVENT_UNTIL(ev==PROCESS_EVENT_TIMER);//即etimer到期繼續(xù)執(zhí)行下面內(nèi)容printf("Hello\n");process_post(&print_world_process,event_data_ready,NULL);//傳遞異步事件給print_world_process,直到內(nèi)核調(diào)度該進程才處理該事件。etimer_reset(&timer);//重置定時器}PROCESS_END();}/*定義進程print_world_process*/PROCESS_THREAD(print_world_process,ev,data){PROCESS_BEGIN();printf("***printworldprocessstart***\n");while(1){PROCESS_WAIT_EVENT_UNTIL(ev==event_data_ready);printf("world\n");}PROCESS_END();}進程print_hello_process一直執(zhí)行到PROCESS_WAIT_EVENT_UNTIL(ev==PROCESS_EVENT_TIMER),此時etimer還沒到期,進程被掛起。轉(zhuǎn)去執(zhí)行print_world_process,待執(zhí)行到PROCESS_WAIT_EVENT_UNTIL(ev==event_data_ready)被掛起(因為print_hello_process還沒post事件)。而后再轉(zhuǎn)去執(zhí)行系統(tǒng)進程etimer_process,若檢測到etimer到期,則繼續(xù)執(zhí)行print_hello_process,打印Hello,并傳遞事件event_data_ready給print_world_process,初始化timer,待執(zhí)行到PROCESS_WAIT_EVENT_UNTIL(while死循環(huán)),再次被掛起。轉(zhuǎn)去執(zhí)行print_world_process,打印world,待執(zhí)行到PROCESS_WAIT_EVENT_UNTIL(ev==event_data_ready)又被掛起。再次執(zhí)行系統(tǒng)進程etimer_process,如此反復執(zhí)行。1、etimer_set函數(shù)//etimer_set(&timer,CLOCK_CONF_SECOND/10);voidetimer_set(structetimer*et,clock_time_tinterval){timer_set(&et->timer,interval);//設置定時器timer,add_timer(et);//將這個etimer加入timerlist}timer_set函數(shù)://用當前時間初始化start,并設置間隔intervalvoidtimer_set(structtimer*t,clock_time_tinterval){t->interval=interval;t->start=clock_time();//returncurrent_clock;}clock_time_tclock_time(void){returncurrent_clock;}staticvolatileclock_time_tcurrent_clock=0;typedefunsignedintclock_time_t;add_timer函數(shù):/*將etimer加入timerlist,并update_time(),即求出下一個到期時間next_expiration*/staticvoidadd_timer(structetimer*timer){structetimer*t;etimer_request_poll();//事實上執(zhí)行process_poll(&etimer_process),即將進程的needspoll設為1,使其獲得更高優(yōu)先級,詳情見下方/*參數(shù)驗證,確保該etimer不是已處理過的*/if(timer->p!=PROCESS_NONE)//如果是PROCESS_NONE,則表示之前處理過,該etimer已到期(注1){for(t=timerlist;t!=NULL;t=t->next){if(t==timer)/*Timeralreadyonlist,bailout.*/{update_time();//即求出下一個到期時間next_expiration(全局靜態(tài)變量),即還有next_expiration時間,就有timer到期return;}}}/*將timer加入timerlist*/timer->p=PROCESS_CURRENT();timer->next=timerlist;timerlist=timer;update_time();//即求出下一個到期時間next_expiration(全局靜態(tài)變量),即還有next_expiration時間,就有timer到期}函數(shù)etimer_request_poll直接調(diào)用process_poll,一步步展開如下:voidetimer_request_poll(void){process_poll(&etimer_process);}voidprocess_poll(structprocess*p){if(p!=NULL){if(p->state==PROCESS_STATE_RUNNING||p->state==PROCESS_STATE_CALLED){p->needspoll=1;poll_requested=1;//全局靜態(tài)變量,標識是否有進程的needspoll為1}}}2、PROCESS_WAIT_EVENT_UNTIL宏//PROCESS_WAIT_EVENT_UNTIL(ev==PROCESS_EVENT_TIMER);/*宏P(guān)ROCESS_WAIT_EVENT_UNTIL,直到條件c為真時,進程才得以繼續(xù)向前推進*/#definePROCESS_WAIT_EVENT_UNTIL(c)PROCESS_YIELD_UNTIL(c)#definePROCESS_YIELD_UNTIL(c)PT_YIELD_UNTIL(process_pt,c)//Yieldthecurrentlyrunningprocessuntilaconditionoccurs#definePT_YIELD_UNTIL(pt,cond)\do\{\PT_YIELD_FLAG=0;\LC_SET((pt)->lc);\//注:保存斷點,下次從這里開始執(zhí)行!??!if((PT_YIELD_FLAG==0)||!(cond)){\returnPT_YIELDED;\}\}while(0)#defineLC_SET(s)s=__LINE__;case__LINE__://保存行數(shù),即lc被設置成該LC_SET所在的行從源代碼可以看出,第一次執(zhí)行PROCESS_WAIT_EVENT_UNTIL總是被掛起(因為PT_YIELD_FLAG==0為真,會直接執(zhí)行returnPT_YIELDED)。該進程下一次被調(diào)試的時候,總是從PROCESS_BEGIN()開始,而PROCESS_BEGIN宏包含兩條語句:其一,將PT_YIELD_FLAG置1;再者,switch(pt->lc),從而跳轉(zhuǎn)到case__LINE__(見上述源碼的注)。接著判斷if條件,此時PT_YIELD_FLAG=1,若條件為真,則不執(zhí)行return,繼續(xù)后續(xù)的內(nèi)容,從而進程接著執(zhí)行。3、process_post函數(shù)源碼如下://process_post(&print_world_process,event_data_ready,NULL);即把事件event_data_ready加入事件隊列intprocess_post(structprocess*p,process_event_tev,process_data_tdata){staticprocess_num_events_tsnum;if(nevents==PROCESS_CONF_NUMEVENTS){returnPROCESS_ERR_FULL;}snum=(process_num_events_t)(fevent+nevents)%PROCESS_CONF_NUMEVENTS;events[snum].ev=ev;events[snum].data=data;events[snum].p=p;++nevents;#ifPROCESS_CONF_STATSif(nevents>process_maxevents){process_maxevents=nevents;}#endifreturnPROCESS_ERR_OK;}4、etimer_reset函數(shù)/*Resetthetimerwiththesameinterval.*/voidetimer_reset(structetimer*et){timer_reset(&et->timer);add_timer(et);//詳情見前面}voidtimer_reset(structtimer*t){t->start+=t->interval;/}實驗步驟及結(jié)果:/r

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論