第6章 嵌入式Linux多任务编程

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

嵌入式应用程序设计第六章嵌入式Linux多任务编程26.1Linux下多任务机制的介绍6.2进程控制编程6.3进程间通信6.4多线程编程6.5实验内容6.6小结6.7思考与练习本章课程:6.1Linux下多任务概述6.1.1任务6.1.2进程6.1.3线程46.1Linux下多任务概述多任务处理是指用户可以在同一时间内运行多个应用程序,每个应用程序被称作一个任务。Linux就是一个支持多任务的操作系统,比起单任务系统它的功能增强了许多。当多任务操作系统使用某种任务调度策略允许两个或更多进程并发共享一个处理器时,事实上处理器在某一时刻只会给一件任务提供服务。因为任务调度机制保证不同任务之间的切换速度十分迅速,因此给人多个任务同时运行的错觉。多任务系统中有3个功能单位:任务、进程和线程。56.1.1任务任务是一个逻辑概念,指由一个软件完成的活动,或者是一系列共同达到某一目的的操作。通常一个任务是一个程序的一次运行,一个任务包含一个或多个完成独立功能的子任务,这个独立的子任务是进程或者是线程。任务、进程和线程之间的关系:66.1.2进程进程是指一个具有独立功能的程序在某个数据集合上的一次动态执行过程,它是系统进行资源分配和调度的基本单元。一次任务的运行可以并发激活多个进程,这些进程相互合作来完成该任务的一个最终目标。进程的特性并发性动态性交互性独立性异步性进程和程序是有本质区别的:程序是静态的一段代码,是一些保存在非易失性存储器的指令的有序集合,没有任何执行的概念;而进程是一个动态的概念,它是程序执行的过程,包括了动态创建、调度和消亡的整个过程,它是程序执行和资源管理的最小单位。76.1.2进程进程的种类:交互式进程批处理进程实时进程Linux下进程结构进程不但包括程序的指令和数据,而且包括程序计数器和处理器的所有寄存器以及存储临时数据的进程堆栈,从而正在执行的进程包括处理器当前的一切活动。86.1.2进程进程状态运行状态可中断的阻塞状态不可中断的阻塞状态可终止的阻塞状态暂停状态跟踪状态僵尸状态僵尸撤销状态96.1.2进程进程状态转换关系:6.1.2进程Linux内核通过惟一的进程标识符PID来标识每个进程。PID存放在进程描述符的pid字段中。在Linux中获得当前进程的进程号(PID)和父进程号(PPID)的系统调用函数分别为getpid()和getppid()。116.1.2进程进程的创建和执行:许多操作系统都提供的是产生进程的机制,也就是首先在新的地址空间里创建进程、读入可执行文件,最后再开始执行。Linux中进程的创建很特别,它把上述步骤分解到两个单独的函数中取执行:fork()和exec函数族。首先,fork()通过拷贝当前进程创建一个子进程,子进程与父进程的区别仅仅在于不同的PID、PPID和某些资源及统计量。exec函数族负责读取可执行文件并将其载入地址空间开始运行。进程的终止:进程终结也需要做很多繁琐的收尾工作,系统必须保证进程所占用的资源回收,并通知父进程。Linux首先把终止的进程设置为僵尸状态,这个时候,进程无法投入运行了,它的存在只为父进程提供信息,申请死亡。父进程得到信息后,开始调用wait函数族,最终赐死子进程,子进程占用的所有资源被全部释放。126.1.2进程进程的内存结构136.1.3线程线程的概念它是进程内独立的一条运行路线,处理器调度的最小单元,也可以称为轻量级进程。线程可以对进程的内存空间和资源进行访问,并与同一进程中的其他线程共享。因此,线程的上下文切换的开销比创建进程小得多。线程与进程间的关系146.1.3线程线程的种类用户级线程轻量级进程内核线程6.2进程控制编程6.2.1进程编程基础6.2.2Linux守护进程166.2.1进程编程基础fork()fork()函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。使用fork()函数得到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文、代码段、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。fork()函数语法:176.2.1进程编程基础exec函数族fork()函数是用于创建一个子进程,该子进程几乎拷贝了父进程的全部内容,但是,这个新创建的进程如何执行呢?这个exec函数族就提供了一个在进程中启动另一个程序执行的方法。exec函数族成员函数语法:186.2.1进程编程基础exec函数族使用区别查找方式表中的前四个函数的查找方式都是完整的文件目录路径,而最后两个函数(以p结尾的函数)可以只给出文件名,系统就会自动从环境变量“$PATH”所指出的路径中进行查找。参数传递方式两种方式:逐个列举、将所有参数整体构造指针数组传递以函数名的第五位字母来区分的,字母为“l”(list)的表示逐个列举的方式,其语法为char*arg;字母为“v”(vertor)的表示将所有参数整体构造指针数组传递,其语法为*constargv[]环境变量exec函数族可以默认系统的环境变量,也可以传入指定的环境变量。这里,以“e”(Enviromen)结尾的两个函数execle、execve就可以在envp[]中指定当前进程所使用的环境变量196.2.1进程编程基础exec函数执行失败,常见原因:找不到文件或路径,此时errno被设置为ENOENT;数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT;没有对应可执行文件的运行权限,此时errno被设置为EACCES。206.2.1进程编程基础exit()和_exit()exit()和_exit()函数都是用来终止进程的。当程序执行到exit()或_exit()时,进程会无条件地停止剩下的所有操作,清除包括各种数据结构,并终止本进程的运行。216.2.1进程编程基础exit()和_exit()的执行过程226.2.1进程编程基础exit()和_exit()的区别_exit()函数的作用是直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。exit()函数与_exit()函数最大的区别就在于exit()函数在终止当前进程之前要检查该进程打开过哪些文件,把文件缓冲区中的内容写回文件,就是图中的“清理I/O缓冲”一项。exit()和_exit函数语法:236.2.1进程编程基础wait()和waitpid()wait()函数是用于使父进程(也就是调用wait()的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结束,则wait()就会立即返回。waitpid()的作用和wait()一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能,也能支持作业控制。wait函数语法:246.2.1进程编程基础wait()和waitpid()waitpid函数语法:256.2.1进程编程基础wait()和waitpid()waitpid实例:开始fork()fork()返回值父进程调用waitpid()子进程暂停5s子进程退出waitpid()返回值父进程暂停5s捕获子进程退出结束返回值=0返回值0返回值0(出错)返回值=0返回值=子进程号266.2.2Linux守护进程守护进程,也就是通常所说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件守护进程常常在系统引导装入时启动,在系统关闭时终止Linux系统有很多守护进程,大多数服务都是用守护进程实现的在Linux中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会被自动关闭。守护进程能够突破这种限制,它从被执行开始运转,直到整个系统关闭才会退出。如果想让某个进程不因为用户或终端或其他的变化而受到影响,就必须把这个进程变成一个守护进程。276.2.2Linux守护进程编写守护进程创建子进程,父进程退出在子进程中创建新会话改变当前目录为根目录重设文件权限掩码关闭文件描述符286.2.2Linux守护进程创建子进程,父进程退出这是编写守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在shell终端里造成一种程序已经运行完毕的假象。之后的所有工作都在子进程中完成,而用户在shell终端里则可以执行其他的命令,从而在形式上做到了与控制终端的脱离。由于父进程已经先于子进程退出,会造成子进程没有父进程,从而变成一个孤儿进程。在Linux中,每当系统发现一个孤儿进程,就会自动由1号进程(也就是init进程)收养它,这样,原先的子进程就会变成init进程的子进程了。实例:pid=fork();if(pid0){exit(0);/*父进程退出*/}296.2.2Linux守护进程在子进程中创建新会话进程组进程组是一个或多个进程的集合。进程组由进程组ID来惟一标识。除了进程号(PID)之外,进程组ID也是一个进程的必备属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID。且该进程ID不会因组长进程的退出而受到影响。会话期会话组是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期306.2.2Linux守护进程在子进程中创建新会话setsid()函数作用:setsid()函数用于创建一个新的会话,并担任该会话组的组长。调用setsid()有下面的3个作用。让进程摆脱原会话的控制。让进程摆脱原进程组的控制。让进程摆脱原控制终端的控制。setsid()函数格式:316.2.2Linux守护进程改变当前目录为根目录通常的做法是让“/”作为守护进程的当前工作目录。使用fork创建的子进程继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统是不能卸载的,这对以后的使用会造成诸多的麻烦(比如进入单用户模式)。326.2.2Linux守护进程重设文件权限掩码文件权限掩码是指屏蔽掉文件权限中的对应位。由于使用fork新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件权限掩码设置为0,可以大大增加该守护进程的灵活性。设置文件权限掩码的函数是umask通常的使用方法为umask(0)336.2.2Linux守护进程关闭文件描述符同文件权限掩码一样,用fork新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下在上面的第二步后,守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护进程,守护进程中用常规的方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1和2的三个文件(常说的输入、输出和报错这三个文件)已经失去了存在的价值,也应被关闭。实例:for(i=0;iMAXFILE;i++){close(i);}346.2.2Linux守护进程Linux守护进程创建流程开始fork()创建子进程exit()使父进程退出setsid()创建新会话chdir(“/”)设置工作目录umask(0)重设文件权限掩码close()关闭文件描述符结束356.2.2Lin

1 / 108
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功