版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第10章嵌入式Linux多任务编程简介10.1进程的基本概念
通常一个任务是一个程序的一次运行,一个任务包含一个或多个完成独立功能的子任务,这个独立的子任务就是进程或线程。对系统而言,当用户在系统中键入命令执行一个程序的时候,它将启动一个进程。一、进程的状态二、进程的标示符在Linux中最主要的进程标识有进程号(PID,ProcessIdenityNumber)和它的父进程号(PPID,parentprocessID)。其中PID惟一地标识一个进程。PID和PPID都是非零的正整数。三、进程的创建、执行和终止1、创建在进程中通过fork()函数通过复制当前进程创建子进程,子进程和父进程只有进程号不同,在发生写入数据时复制资源。2、执行由exec函数族负责读取可执行文件将其载入地址空间运行。3、终止释放资源、进入僵尸状态,通知父进程,由父进程终止。四、进程的内存结构Linux操作系统采用虚拟内存技术,每个进程都有各自互不干涉的内存空间,每个进程具有4GB的虚拟内存空间。虚拟内存空间分为用户空间(0~3GB),内核空间(3~4GB).10.2进程控制编程一、创建新进程通过调用fork()函数在父进程中创建子进程,子进程继承父进程的地址空间,复制了父进程中的代码段、数据段和堆栈段的大部分内容。所独有的只是进程号、资源使用和计数器等。两个进程同时运行,都获得fork()的返回值。1、fork()函数所需头文件#include<sys/types.h>#include<unistd.h>函数原型pid_tfork(void)函数返回值0:子进程子进程ID(大于0的整数):父进程-1:出错-/*fork.c*/#include<sys/types.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>intmain(void){pid_tresult;/*调用fork函数,其返回值为result*/result=fork();/*通过result的值来判断fork函数的返回情况,首先进行出错处理*/if(result==-1){perror("fork");exit;}/*返回值为0代表子进程*/elseif(result==0){printf("Thereturnvalueis%d\nInchildprocess!!\nMyPIDis%d\n",result,getpid());}/*返回值大于0代表父进程*/else{printf("Thereturnvalueis%d\nInfatherprocess!!\nMyPIDis%d\n",result,getpid());}}现在大部分嵌入式Linux系统采用vfork()函数创建子进程,vfork()创建的子进程与父进程可以访问相同的物理内存,只有子进程需要改变内存数据是才复制父进程。2、exec函数族
exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。在Linux中使用exec函数族主要有两种情况:当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用任何exec函数族让自己重生;如果一个进程想执行另一个程序,那么它就可以调用fork()函数新建一个进程,然后调用任何一个exec,这样看起来就好像通过执行应用程序而产生了一个新进程exec函数族成员函数语法所需头文件#include<unistd.h>函数原型intexecl(constchar*path,constchar*arg,...)intexecv(constchar*path,char*constargv[])intexecle(constchar*path,constchar*arg,...,char*constenvp[])intexecve(constchar*path,char*constargv[],char*constenvp[])intexeclp(constchar*file,constchar*arg,...)intexecvp(constchar*file,char*constargv[])函数返回值-1:出错/*execl.c*/#include<unistd.h>#include<stdio.h>#include<stdlib.h>intmain(){if(fork()==0){/*调用execl函数,注意这里要给出ps程序所在的完整路径*/if(execl("/bin/ps","ps","-ef",NULL)<0)perror("execlerror!");}}3、exit和_exitexit和_exit函数都是用来终止进程的。当程序执行到exit或_exit时,进程会无条件地停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。但是,这两个函数还是有区别的。_exit()函数的作用是:直接使进程停止运行,清除其使用的内存空间,并清除其在内核中的各种数据结构;exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。exit()函数与_exit()函数最大的区别就在于exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件。exit和_exit函数族语法所需头文件exit:#include<stdlib.h>_exit:#include<unistd.h>函数原型exit:voidexit(intstatus)_exit:void_exit(intstatus)函数传入值status是一个整型的参数,可以利用这个参数传递进程结束时的状态。一般来说,0表示正常结束;其他的数值表示出现了错误,进程非正常结束。在实际编程时,可以用wait系统调用接收子进程的返回值,从而针对不同的情况进行不同的处理在一个进程调用了exit之后,该进程并不马上就完全消失,而是留下一个称为僵尸进程(Zombie)的数据结构。僵尸进程是一种非常特殊的进程,它几乎已经放弃了所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。4、wait和waitpidwait函数是用于使父进程(也就是调用wait的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则wait就会立即返回。waitpid的作用和wait一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait功能,也能支持作业控制。实际上wait函数只是waitpid函数的一个特例,在Linux内部实现wait函数时直接调用的就是waitpid函数。wait函数族语法所需头文件#include<sys/types.h>#include<sys/wait.h>函数原型pid_twait(int*status)函数传入值这里的status是一个整型指针,是该子进程退出时的状态·status若为空,则代表任意状态结束的子进程·status若不为空,则代表指定状态结束的子进程另外,子进程的结束状态可由Linux中一些特定的宏来测定函数返回值成功:子进程的进程号失败:-1所需头文件#include<sys/types.h>#include<sys/wait.h>函数原型pid_twaitpid(pid_tpid,int*status,intoptions)函数传入值pidpid>0:只等待进程ID等于pid的子进程,不管已经有其他子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去pid=-1:等待任何一个子进程退出,此时和wait作用一样pid=0:等待其组ID等于调用进程的组ID的任一子进程pid<-1:等待其组ID等于pid的绝对值的任一子进程status同waitoptionsWNOHANG:若由pid指定的子进程不立即可用,则waitpid不阻塞,此时返回值为0waitpid函数语法optionsWUNTRACED:若实现某支持作业控制,则由pid指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态0:同wait,阻塞父进程,等待子进程退出函数返回值正常:子进程的进程号使用选项WNOHANG且没有子进程退出:0调用出错:-1/*waitpid.c*/#include<sys/types.h>#include<sys/wait.h>#include<unistd.h>#include<stdio.h>#include<stdlib.h>intmain(){pid_tpc,pr;pc=fork();if(pc<0)printf("Errorfork.\n");/*子进程*/elseif(pc==0){/*子进程暂停5s*/sleep(5);/*子进程正常退出*/exit(0);}/*父进程*/else{/*循环测试子进程是否退出*/do{/*调用waitpid,且父进程不阻塞*/pr=waitpid(pc,NULL,WNOHANG);/*若子进程还未退出,则父进程暂停1s*/if(pr==0){printf("Thechildprocesshasnotexited\n");sleep(1);}}while(pr==0);/*若发现子进程退出,打印出相应情况*/if(pr==pc)printf("Getchild%d\n",pr);elseprintf("someerroroccured.\n");}}10.3进程间的通信
进程是一个程序的一次执行的过程。这里所说的进程一般是指运行在用户态的进程,而由于处于用户态的不同进程之间是彼此隔离的,它们必须通过某种方式来进行通信,传递信息和数据。系统中多个进程间可能存在3种关系:1、资源共享多个任务间没有直接联系,但这些任务运行时,会使用某些公共资源,而这些资源往往数量有限,甚至只能独占使用。共享外部设备:多个进程同时访问独占性外部设备。2、相互合作为完成某些大型应用程序,每个进程完成一种功能,多个进程必须相互合作,才能完成全部功能。3、相互无关进程之间无任何关系,无共享资源,也没有时间、空间和功能上的合作,可分别独立运行。
一、进程间通信有如下一些目的:数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几兆字节之间。共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。二、Linux下进程间通信的几种主要方式:1、共享内存
使得多个进程可以访问同一块内存空间,在通信前,进程A可以向系统申请创建一个共享内存,若创建成功,系统返回共享内存的标示符给任务A。所有任务都可以使用该标识符把该共享内存链接到自己的地址空间,此后进程就可以像操作普通存储区一样访问共享内存。从而大大提高了效率。当然,由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等。共享内存的实现分为两个步骤,第一步是创建共享内存,这里用到的函数是shmget,也就是从内存中获得一段共享内存区域。第二步映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间去,这里使用的函数是shmat。到这里,就可以使用这段共享内存了,也就是可以使用不带缓冲的I/O读写命令对其进行操作。除此之外,当然还有撤销映射的操作,其函数为shmdt。2、信号它是在软件层次上对中断机制的一种模拟,是一种异步通信方式。信号可以直接进行用户空间进程和内核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。它可以在任何时候发给某一进程,而无需知道该进程的状态。如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它为止;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。(2)信号的响应方式忽略信号。但不能忽略SIGKILL、SIGSTOP。捕捉信号。定义信号处理函数。执行默认操作。(1)信号的产生a、硬件来源:硬件异常、除数为零、存储器访问越界、电源失效等,由内核产生并发送到相关进程。b、软件来源:如SIGALRM(进程设置的闹钟超时)、SIGPIPE(管道的读进程终止后一个进程写此管道)进程使用kill()和raise()等函数3、消息队列
消息队列就是一个消息的列表。用户可以从消息队列种添加消息、读取消息等。从这点上看,消息队列具有一定的FIFO的特性,但是它可以实现消息的随机查询,比FIFO具有更大的优势。同时,这些消息又是存在于内核中的,由“队列ID”来标识。
消息队列的实现包括创建或打开消息队列、添加消息、读取消息和控制消息队列这四种操作。其中创建或打开消息队列使用的函数是msgget,添加消息使用的函数是msgsnd函数,它把消息添加到已打开的消息队列末尾;读取消息使用的函数是msgrcv,它把消息从消息队列中取走,与FIFO不同的是,这里可以指定取走某一条消息;最后控制消息队列使用的函数是msgctl,它可以完成多项功能。管道是Linux中进程间通信的一种方式。它具有如下特点。无名管道只能用于具有亲缘关系的进程之间的通信(也就是父子进程或者兄弟进程之间)。它是一个半双工的通信模式,具有固定的读端和写端。管道也可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信;4、管道及有名管道通常先是创建一个管道,再通过fork()函数创建一子进程,该子进程会继承父进程所创建的管道,这时,父子进程管道的文件描述符对应关系就如图所示。ADS(ARMDeveloperSuite)是ARM公司推出的关于ARM处理器的编译、链接和调试的集成开发环境。
ADS将编译和链接集成一个环境中,简称CodeWarriorforADS;将仿真调试环境集成在一个称为ARMextendedDebugger的环境中,简称AXD.
两个环境都同时提供了图形环境和命令行环境,两者各有特色。第11章ADS集成开发环境简介ARMADS由六部分组成:
代码生成工具(CodeGenerationTools)代码生成工具由源程序编译、汇编、链接工具集组成。ARM公司针对ARM系列每一种结构都进行了专门的优化处理,这一点除了作为ARM结构的设计者的ARM公司,其他公司都无法办到,ARM公司宣称,其代码生成工具最终生成的可执行文件最多可以比其他公司工具套件生成的文件小20%。
集成开发环境(CodeWarriorIDEfromMetrowerks)
CodeWarriorIDE是Metrowerk
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 产教融合人才培养共同体的构建目标
- 三角形-三角形的特性说课稿-2023-2024学年四年级下册数学人教版
- 2025年幼儿园中班班务计划开头语模板
- 2025年皮肤科医师工作计划
- Unit 4 Plants around us Start to read and Reading time(说课稿)-2024-2025学年人教PEP版(2024)英语三年级上册
- 2025年学校教师教学个人工作计划
- 毕业活动主题策划方案合集
- Unit 2 My week Part C(说课稿)-2024-2025学年人教PEP版英语五年级上册
- Unit 2 My name(单元整体说课稿)-2024-2025学年科普版(2024)英语三年级上册
- 从编码到解码(说课稿)2024-2025学年四年级上册信息技术苏科版
- 2024年06月上海广发银行上海分行社会招考(622)笔试历年参考题库附带答案详解
- TSG 51-2023 起重机械安全技术规程 含2024年第1号修改单
- 计算机科学导论
- 2024-2025学年六上科学期末综合检测卷(含答案)
- 圆管钢立柱柱吊装施工方案
- 河南省对口升学文秘类专业课试题卷
- 医疗器械经营质量管理体系文件(全套)
- 磷酸铁锂电池工商业储能项目施工组织设计方案
- 建筑节能分部工程质量验收报告(样本)
- 泌尿外科护理疑难病例讨论
- 英格索兰空压机操作规程
评论
0/150
提交评论