资源预览内容
第1页 / 共81页
第2页 / 共81页
第3页 / 共81页
第4页 / 共81页
第5页 / 共81页
第6页 / 共81页
第7页 / 共81页
第8页 / 共81页
第9页 / 共81页
第10页 / 共81页
亲,该文档总共81页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
,嵌入式Linux进程和线程编程,www.embedu.org,课程目标,进程相关的基本概念 Linux进程的创建 Linux进程的管理和守护进程 Linux进程间通信的方式 Linux中线程创建和退出 Linux中线程间的同步和互斥,www.embedu.org,本章内容,6.1 Linux进程概述 6.2 Linux进程控制相关API 6.3 ARM Linux进程间通信 6.4 ARM Linux线程相关API 6.5 Linux守护进程 本章小结,www.embedu.org,6.1 Linux进程概述,6.1.1 进程描述符及任务结构 6.1.2 进程的调度 6.1.3 Linux中的线程,www.embedu.org,6.1.1 进程描述符及任务结构,进程概念 进程的概念首先在20世纪60年代初期由MIT的Multics系统和IBM的TSS/360系统中引入的。 (1)进程是一个独立的可调度的活动(E.Cohen,D.Jofferson)。 (2)进程是一个抽象实体,当它执行某个任务时,将要分配和释放各种资源(P.Denning)。 (3)进程是可以并行执行的计算部分(S.E.Madnick,J.T.Donovan)。 进程和程序有本质的区别:程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念;而进程是一个动态的概念,它是程序执行的过程,包括了动态创建、调度和消亡的整个过程,它是程序执行和资源管理的最小单位。,www.embedu.org,6.1.1 进程描述符及任务结构,Linux中进程描述符 进程不但包括程序的指令和数据,而且包括程序计数器和CPU的所有寄存器以及存储临时数据的进程堆栈。 内核把进程存放在任务队列(task list)的双向循环链表中,其中链表的每一项都是类型为task_struct,称为进程描述符的结构,该结构定义在中 。,www.embedu.org,6.1.1 进程描述符及任务结构,Linux中进程描述符 Linux通过slab分配器分配task_struct结构,它实际上是一个栈,其栈顶(向上增长的栈)或栈底(向下增长的栈)中有一个thread info结构,其中的task指针指向task_struct。 下面详细讲解task_struct结构中最为重要的两个域:state和pid。,www.embedu.org,6.1.1 进程描述符及任务结构,Linux中进程描述符 (1)进程状态,运行 (TASK_RUNNING) 可中断 (TASK_INTERUPTIBLE) 不可中断 (TASK_UNINTERUPTIBLE) 僵死 (TASK_ZOMBIE) 停止 (TASK_STOPPED),www.embedu.org,6.1.1 进程描述符及任务结构,Linux中进程描述符 (2)任务标识 Linux内核通过惟一的进程标识值PID来标识每个进程。PID是一个非负数,它实际上是一个短整型数据,也就是说它最大值为32767。读者可以查看/proc/sys/kernel/pid_max来确定该系统的进程数上限。一般来说,32767对于很多桌面系统已经足够,但是对于大型服务器,就必须修改这个上限。,www.embedu.org,6.1.1 进程描述符及任务结构,进程的创建、执行和终止 (1)进程的创建和执行 许多操作系统都提供的是产生进程的机制,也就是首先在新的地址空间里创建进程、读入可执行文件,最后再开始执行。 首先,fork()通过拷贝当前进程的内容创建一个子进程,子进程与父进程的区别仅仅在于不同的PID、PPID和其他一些资源。 exec函数负责读取可执行文件并将其载入地址空间开始运行。,www.embedu.org,6.1.1 进程描述符及任务结构,进程的创建、执行和终止 (2)进程的终止 进程终结也需要做很多繁琐的收尾工作,系统必须保证进程所占用的资源回收,并通知父进程。 Linux首先把终止的进程设置为僵死状态,这个时候,进程无法投入运行了。它的存在只为父进程提供信息,申请死亡。父进程得到信息后,开始调用wait (),子进程占用的资源被全部释放。,www.embedu.org,6.1.2 进程的调度,Linux中进程调度概述 Linux中进程调度算法,www.embedu.org,Linux中进程调度概述,进程调度是指确定CPU当前执行哪个进程。Linux进程调度策略是以优先级调度为基础的,即优先运行优先级最高的进程。根据优先级的范围,可以把进程分为实时进程(这里的实时是软实时)和普通进程。实时进程优先级高于普通进程,并由特定的调度策略来保证它们的(软)实时性。 内核中的默认配置是:进程优先级在0139,其中实时进程占用099,一般进程占用100139。 在调度时,系统总是首先选取具有最高优先级的并且拥有活跃进程的进程组,然后进行相同优先级下的进程调度。,www.embedu.org,Linux中进程调度算法,Linux 2.6内核中实现了一个O(1)的调度算法,也就是说每一次调度所需要的时间与该CPU内的总进程数无关 。 Linux中每个运行队列都有两个优先级数组,一个活跃的和一个过期的。优先级数组在kernel/sched.c中被定义,它是prio_array类型的结构体。,struct prio_array unsigned int nr_active; /* 当前活跃的进程总数 */ unsigned long bitmapBITMAP_SIZE; /* 活跃进程的位图 */ struct list_head queueMAX_PRIO; /* 各个优先级队列的头指针组成的数组*/ ;,www.embedu.org,6.1.3 Linux中的线程,线程机制是现代编程技术中常用的一种抽象,该机制提供了在同一程序内共享内存地址空间运行的一组线程。这些线程可以共享打开的文件和其他资源等。 Linux中实现线程的机制非常独特。从内核的角度来说,它并没有线程这个概念。Linux把线程都当作进程来实现,仅仅将其视为使用某些共享资源的进程。每个线程都用有惟一隶属于自己的task_struct,所以在内核中,它看起来就像一个普通的进程 。,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 fork (1)fork函数说明 执行一次却返回两个值,父进程的返回值是子进程的进程号,而子进程则返回0 。 (2)fork函数语法 fork函数的语法格式如下所示。 头文件 #include / 提供类型pid_t的定义 #include 函数原型 pid_t fork(void); 函数返回值 0:子进程 子进程ID(大于0的整数):父进程 -1:出错,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 (3)fork函数调用实例 /*调用fork函数,其返回值赋给result*/ int result = fork(); /*通过result的值来判断fork函数的返回情况,首先进行出错处理*/ if(result = -1) perror(“fork“); exit(-1); /*返回值为0代表子进程*/ else if(result = 0) /*子进程相关语句*/ /*返回值大于0代表父进程*/ else /*父进程相关语句*/ ,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 exec函数族 (1)exec函数族说明 fork函数是用于创建一个子进程,该子进程几乎拷贝了父进程的全部内容。 exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的路径和文件名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 exec函数族 (2)exec函数族语法 实际上,在Linux中并没有exec()函数,而是以exec开头的函数族,它们之间语法有细微差别。 exec函数族语法格式如下所示。 头文件 #include 函数原型 int execl(const char *path, const char *arg, .); int execv(const char *path, char *const argv); int execle(const char *path, const char *arg, ., char *const envp); int execve(const char *path, char *const argv, char *const envp); int execlp(const char *file, const char *arg, .); int execvp(const char *file, char *const argv); 函数返回值 出错1:-1,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 exec函数族 (2)exec函数族语法,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 exec函数族 (3)exec函数组调用实例 使用execlp函数,采用逐个列举方式,并且使用系统默认的环境变量。 使用execl函数时需要给出完整的文件路径来查找对应的可执行文件。,if(fork()=0) /*调用execlp函数,这里相当于调用了“ls -l”命令*/ if(execlp(“ls“,“ls“,“-l“,NULL)0) perror(“execlp error!“); ,/*调用execl函数,注意这里要给出ls程序所在的完整路径*/ if(execl(“/bin/ls“,“ls“,“-l“,NULL)0) perror(“execl error!“);,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 exec函数族 (3)exec函数组调用实例 使用execle时可以将环境变量添加到新建的子进程中去 使用execve函数时,通过构造指针数组的方式来传递参数,注意参数列表一定要以NULL作为结尾标识符。,/*命令参数列表,必须以NULL结尾*/ char *envp=“PATH=/tmp“,“USER=sunq“,NULL; /*调用execle函数,注意这里也要指出env的完整路径*/ if(execle(“/bin/env“,“env“,NULL,envp)0) perror(“execle error!“);,/*命令参数列表,必须以NULL结尾*/ char *arg=“env“,NULL; char *envp=“PATH=/tmp“,“USER=sunq“,NULL; if(execve(“/bin/env“,arg,envp)0) perror(“execve error!“);,www.embedu.org,6.2 Linux进程控制相关API,进程的创 建 exit和_exit (1)exit和_exit函数说明 exit和_exit函数都是用来终止进程的。当程序执行到exit或_exit时,进程会无条件地停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。 exit()函数与_exit()函数的区别就在于exit()函数在调用exit系统调用之前要检查进程中文件的打开情况,把文件缓冲区中的内容写回文件。 如果用_exit()函数直接将进程关闭,缓冲区中的数据就会丢失。因此,若想保证数据的完整性,
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号