嵌入式Linux操作系统第2章2

上传人:pu****.1 文档编号:591445281 上传时间:2024-09-17 格式:PPT 页数:134 大小:1.83MB
返回 下载 相关 举报
嵌入式Linux操作系统第2章2_第1页
第1页 / 共134页
嵌入式Linux操作系统第2章2_第2页
第2页 / 共134页
嵌入式Linux操作系统第2章2_第3页
第3页 / 共134页
嵌入式Linux操作系统第2章2_第4页
第4页 / 共134页
嵌入式Linux操作系统第2章2_第5页
第5页 / 共134页
点击查看更多>>
资源描述

《嵌入式Linux操作系统第2章2》由会员分享,可在线阅读,更多相关《嵌入式Linux操作系统第2章2(134页珍藏版)》请在金锄头文库上搜索。

1、嵌入式嵌入式嵌入式嵌入式LinuxLinux操作系统操作系统操作系统操作系统第第2章章 Linux编程基础编程基础 Linux下的下的C语言编程语言编程 1 1VIM编辑器编辑器 2 2GCC编译器编译器 3 3GDB调试器调试器 4 4Make工程管理器工程管理器 5 5第第2章章 Linux编程基础编程基础 Linux下的集成开发环境下的集成开发环境 6 6文件文件I/O编程编程 7 7进程控制编程进程控制编程 8 8进程间的通信和同步进程间的通信和同步 9 9多线程编程多线程编程 1010Linux下的集成开发环境下的集成开发环境v集成开发环境是将一些开发工具集合到同一个操作界面的集成开

2、发环境是将一些开发工具集合到同一个操作界面的工具软件,它通常由项目管理器、文件管理器、文本编辑工具软件,它通常由项目管理器、文件管理器、文本编辑工具、语法纠正器、编译工具、调试工具组成。工具、语法纠正器、编译工具、调试工具组成。v在在Linux系统中开发系统中开发C、C+语言程序,可选择的集成开发语言程序,可选择的集成开发环境有环境有Eclipse和和Kdevelop,分别运行在,分别运行在GNOME桌面环境桌面环境和和KDE桌面环境。桌面环境。vLinux系统下的集成开发环境通常自身不包含编译器和调系统下的集成开发环境通常自身不包含编译器和调试器,而是直接利用试器,而是直接利用GCC、GDB

3、等工具进行组合。工具等工具进行组合。工具组合正代表了组合正代表了Linux系统上软件设计的思想。系统上软件设计的思想。Linux下的集成开发环境下的集成开发环境vKdevelop是一个支持多种程序设计语言的集成开发环境,它运行在是一个支持多种程序设计语言的集成开发环境,它运行在KDE桌面环境,可支持桌面环境,可支持C、C+语言程序发开。语言程序发开。Kdevelop很好的支持很好的支持了了Qt图形界面工具包,因此是开发图形界面工具包,因此是开发KDE桌面工具的理想环境。用于开桌面工具的理想环境。用于开发发C、C+语言程序时,它的主要特性如下:语言程序时,它的主要特性如下:v源代码高亮显示,源代

4、码高亮显示,Kdevelop的编译功能和调试功能该编辑器支持源代的编译功能和调试功能该编辑器支持源代码高亮显示和自动缩进的功能码高亮显示和自动缩进的功能.。v项目管理,项目管理器可以管理各种不同的项目类型,。项目管理,项目管理器可以管理各种不同的项目类型,。v类浏览器,该功能可在进行面向对象开发时,快速了解对象的结构。类浏览器,该功能可在进行面向对象开发时,快速了解对象的结构。vGUI设计器,可进行可见即可得的方式编辑软件的图形界面。设计器,可进行可见即可得的方式编辑软件的图形界面。v并行版本控制,支持并行版本控制,支持CVS、Subversion、Perforce和和ClearCase等常用

5、等常用版本控制工具。版本控制工具。Linux下的集成开发环境下的集成开发环境vEclipse最初是由最初是由IBM公司开发,公司开发,2001年年11月正式贡献给开源社区,现月正式贡献给开源社区,现在由非营利软件供应商联盟在由非营利软件供应商联盟Eclipse基金会管理。基金会管理。2003年,年,OSGi服务服务平台规范成为平台规范成为Eclipse运行时架构。最初运行时架构。最初Eclipse用于开发用于开发Java语言程序,语言程序,但加入但加入CDT插件后就能进行插件后就能进行C和和C+语言程序开发,并具备如下特性:语言程序开发,并具备如下特性:v显示提纲,显示提纲,Outline窗口

6、模块可显示源代码中的过程、变量、声明以及窗口模块可显示源代码中的过程、变量、声明以及函数的位置。函数的位置。v源代码辅助,可结合上下文提示需要输入的源代码,并检查源代码中源代码辅助,可结合上下文提示需要输入的源代码,并检查源代码中的语法错误。的语法错误。v源代码模板,扩展源代码辅助功能中使用的源代码标准,加入自定义源代码模板,扩展源代码辅助功能中使用的源代码标准,加入自定义的源代码段,可加快代码编辑速度。的源代码段,可加快代码编辑速度。v源代码历史记录,在没有使用源代码历史记录,在没有使用CVS等版本控制工具的情况下,也可记等版本控制工具的情况下,也可记录源代码的修改情况。录源代码的修改情况。

7、Linux下的集成开发环境下的集成开发环境vEclipse运行需要运行需要JRE支持,所以首先要确保系统中已安装支持,所以首先要确保系统中已安装JRE。Eclipse首次运行要求配置工作目录首次运行要求配置工作目录workspace,这个目录是默,这个目录是默认用来存放源代码与相关项目文件的位置,当前用户必须有该认用来存放源代码与相关项目文件的位置,当前用户必须有该目录读写和执行的权限。目录读写和执行的权限。Linux下的集成开发环境下的集成开发环境vEclipse界面由数个视图窗格组成。界面由数个视图窗格组成。v左边是左边是Project Explorer视图,该视图用于创建、选择和删视图,

8、该视图用于创建、选择和删除项目。除项目。v正中是编辑器区域,该区域用于编辑源代码,可同时打开正中是编辑器区域,该区域用于编辑源代码,可同时打开多个文件。多个文件。v右侧是右侧是Outline视图,在编辑器中显示文档的大纲,这个大视图,在编辑器中显示文档的大纲,这个大纲的内容取决于源文件的类型。对于纲的内容取决于源文件的类型。对于C和和C+源代码文件,源代码文件,该大纲将显示所有被包含的函数库、函数、常量、变量、该大纲将显示所有被包含的函数库、函数、常量、变量、已声明的类、属性和方法等信息。已声明的类、属性和方法等信息。Linux下的集成开发环境下的集成开发环境v编译与运行源代码前,首先需要保证

9、编译与运行源代码前,首先需要保证GCC、G+编译器和编译器和GDB调试器已安装。调试器已安装。Eclipse通过调用通过调用GCC、G+编译器实现源代码编译器实现源代码编译,因此必须要将源代码的相关信息建立为项目文件,这样编译,因此必须要将源代码的相关信息建立为项目文件,这样才能使才能使Eclipse知道该使用哪一个编译指令。知道该使用哪一个编译指令。Linux下的集成开发环境下的集成开发环境vEclipse的的Debug功能是调用功能是调用GDB调试器实现的,与调试器实现的,与GDB的的命令行不同,命令行不同,Eclipse提供了更友好的图形界面查看调试信提供了更友好的图形界面查看调试信息。

10、要在代码中加入断点,可直接在文本编辑区右击左侧息。要在代码中加入断点,可直接在文本编辑区右击左侧区域弹出的菜单中操作。然后单击区域弹出的菜单中操作。然后单击Run|Debug命令菜单,命令菜单,进入进入Debug界面。界面。文件文件I/O编程编程 v所谓系统调用是指操作系统提供给用户程序调用的一组所谓系统调用是指操作系统提供给用户程序调用的一组“特殊特殊”接口,接口,用户程序可以通过这组用户程序可以通过这组“特殊特殊”接口来获得操作系统内核提供的服务。接口来获得操作系统内核提供的服务。例如用户可以通过进程控制相关的系统调用来创建进程、实现进程调例如用户可以通过进程控制相关的系统调用来创建进程、

11、实现进程调度、进程管理等。度、进程管理等。v为什么用户程序不能直接访问系统内核提供的服务呢?这是由于在为什么用户程序不能直接访问系统内核提供的服务呢?这是由于在Linux中,为了更好地保护内核空间,将程序的运行空间分为内核空中,为了更好地保护内核空间,将程序的运行空间分为内核空间和用户空间(也就是常称的内核态和用户态),它们分别运行在不间和用户空间(也就是常称的内核态和用户态),它们分别运行在不同的级别上,在逻辑上是相互隔离的。因此,用户进程在通常情况下同的级别上,在逻辑上是相互隔离的。因此,用户进程在通常情况下不允许访问内核数据,也无法使用内核函数,它们只能在用户空间操不允许访问内核数据,也

12、无法使用内核函数,它们只能在用户空间操作用户数据,调用用户空间的函数。作用户数据,调用用户空间的函数。v但是,在有些情况下,用户空间的进程需要获得一定的系统服务(调但是,在有些情况下,用户空间的进程需要获得一定的系统服务(调用内核空间程序),这时操作系统就必须利用系统提供给用户的用内核空间程序),这时操作系统就必须利用系统提供给用户的“特特殊接口殊接口”系统调用规定用户进程进入内核空间的具体位置。进行系统调用规定用户进程进入内核空间的具体位置。进行系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后系统调用时,程序运行空间需要从用户空间进入内核空间,处理完后再返回到用户空间。再返回到用

13、户空间。 文件文件I/O编程编程v前面讲到的系统调用并不是直接与程序员进行交互的,它前面讲到的系统调用并不是直接与程序员进行交互的,它仅仅是一个通过软中断机制向内核提交请求,以获取内核仅仅是一个通过软中断机制向内核提交请求,以获取内核服务的接口。在实际使用中程序员调用的通常是用户编程服务的接口。在实际使用中程序员调用的通常是用户编程接口接口API v系统命令相对系统命令相对API更高了一层,它实际上一个可执行程序,更高了一层,它实际上一个可执行程序,它的内部引用了用户编程接口(它的内部引用了用户编程接口(API)来实现相应的功能。)来实现相应的功能。 文件文件I/O编程编程v内核如何区分和引用

14、特定的文件呢?这里用到一个重要的内核如何区分和引用特定的文件呢?这里用到一个重要的概念概念文件描述符文件描述符。对于。对于Linux而言,所有对设备和文件而言,所有对设备和文件的操作都是使用文件描述符来进行的。文件描述符是一个的操作都是使用文件描述符来进行的。文件描述符是一个非负的整数,它是一个索引值,并指向在内核中每个进程非负的整数,它是一个索引值,并指向在内核中每个进程打开文件的记录表。当打开一个现存文件或创建一个新文打开文件的记录表。当打开一个现存文件或创建一个新文件时,内核就向进程返回一个文件描述符;当需要读写文件时,内核就向进程返回一个文件描述符;当需要读写文件时,也需要把文件描述符

15、作为参数传递给相应的函数。件时,也需要把文件描述符作为参数传递给相应的函数。v通常,一个进程启动时,都会打开通常,一个进程启动时,都会打开3个文件:标准输入、个文件:标准输入、标准输出和标准出错处理。标准输出和标准出错处理。文件描述符文件描述符宏宏标准输入标准输入0STDIN_FILENO 标准输出标准输出1STDOUT_FILENO 标准出错标准出错2STDERR_FILENO 文件文件I/O编程编程vopen()函数是用于打开或创建文件,在打开或创建文件时函数是用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数。可以指定文件的属性及用户的权限等各种参数。所需头文

16、件:所需头文件:#include #include #include 原型:原型:int open(const char *pathname, int flags, int perms ) 文件文件I/O编程编程vopen函数语法要点函数语法要点文件文件I/O编程编程vclose()函数是用于关闭一个被打开的文件。当一个进程终函数是用于关闭一个被打开的文件。当一个进程终止时,所有被它打开的文件都由内核自动关闭,很多程序止时,所有被它打开的文件都由内核自动关闭,很多程序都使用这一功能而不显示地关闭一个文件。都使用这一功能而不显示地关闭一个文件。文件文件I/O编程编程vread()函数是用于将从指

17、定的文件描述符中读出的数据放函数是用于将从指定的文件描述符中读出的数据放到缓存区中,并返回实际读入的字节数。若返回到缓存区中,并返回实际读入的字节数。若返回0,则表,则表示没有数据可读,即已达到文件尾。读操作从文件的当前示没有数据可读,即已达到文件尾。读操作从文件的当前指针位置开始。当从终端设备文件中读出数据时,通常一指针位置开始。当从终端设备文件中读出数据时,通常一次最多读一行。次最多读一行。文件文件I/O编程编程vwrite()函数是用于向打开的文件写数据,写操作从文件的函数是用于向打开的文件写数据,写操作从文件的当前指针位置开始。对磁盘文件进行写操作,若磁盘已满当前指针位置开始。对磁盘文

18、件进行写操作,若磁盘已满或超出该文件的长度,则或超出该文件的长度,则write()函数返回失败。函数返回失败。文件文件I/O编程编程vlseek()函数是用于在指定的文件描述符中将文件指针定位函数是用于在指定的文件描述符中将文件指针定位到相应的位置。它只能用在可定位(可随机访问)文件操到相应的位置。它只能用在可定位(可随机访问)文件操作中。管道、套接字和大部分字符设备文件是不可定位的,作中。管道、套接字和大部分字符设备文件是不可定位的,所以在这些文件的操作中无法使用所以在这些文件的操作中无法使用lseek()调用。调用。文件文件I/O编程编程v前面讲述的系统调用是操作系统直接提供的函数接前面讲

19、述的系统调用是操作系统直接提供的函数接口。因为运行系统调用时,口。因为运行系统调用时,Linux必须从用户态切必须从用户态切换到内核态,执行相应的请求,然后再返回到用户换到内核态,执行相应的请求,然后再返回到用户态,所以应该尽量减少系统调用的次数,从而提高态,所以应该尽量减少系统调用的次数,从而提高程序的效率。程序的效率。v标准标准I/O提供流缓冲的目的是尽可能减少使用提供流缓冲的目的是尽可能减少使用read()和和write()等系统调用的数量。等系统调用的数量。文件文件I/O编程编程v标准标准I/O提供了提供了3种类型的缓冲存储。种类型的缓冲存储。v全缓冲全缓冲:在这种情况下,当填满标准:

20、在这种情况下,当填满标准I/O缓存后才进行实际缓存后才进行实际I/O操作。对于存放在磁盘上的文件通常是由标准操作。对于存放在磁盘上的文件通常是由标准I/O库实施全缓冲库实施全缓冲的。的。v 行缓冲行缓冲:在这种情况下,当在输入和输出中遇到行结束符时,:在这种情况下,当在输入和输出中遇到行结束符时,标准标准I/O库执行库执行I/O操作。这允许我们一次输出一个字符(如操作。这允许我们一次输出一个字符(如fputc()函数),但只有写了一行之后才进行实际函数),但只有写了一行之后才进行实际I/O操作。标准输入操作。标准输入和标准输出就是使用行缓冲的典型例子。和标准输出就是使用行缓冲的典型例子。v 不

21、带缓冲不带缓冲:标准:标准I/O库不对字符进行缓冲。如果用标准库不对字符进行缓冲。如果用标准I/O函数函数写若干字符到不带缓冲的流中,则相当于用系统调用写若干字符到不带缓冲的流中,则相当于用系统调用write()函函数将这些字符全写到被打开的文件上。标准出错数将这些字符全写到被打开的文件上。标准出错stderr通常是通常是不带缓存的,这就使得出错息可以尽快显示出来,而不管它们不带缓存的,这就使得出错息可以尽快显示出来,而不管它们是否含有一个行结束符。是否含有一个行结束符。文件文件I/O编程编程v打开文件:三个标准函数打开文件:三个标准函数fopen()、fdopen()和和freopen()。

22、它们可以以不同的模式打开,但都返回一个指向它们可以以不同的模式打开,但都返回一个指向FILE的的指针,该指针指向对应的指针,该指针指向对应的I/O流。此后,对文件的读写都流。此后,对文件的读写都是通过这个是通过这个FILE指针来进行。其中指针来进行。其中fopen()可以指定打开可以指定打开文件的路径和模式,文件的路径和模式,fdopen()可以指定打开的文件描述符可以指定打开的文件描述符和模式,而和模式,而freopen()除可指定打开的文件、模式外,还可除可指定打开的文件、模式外,还可指定特定的指定特定的I/O流。流。文件文件I/O编程编程v其中,其中,mode定义打开文件的访问权限:定义

23、打开文件的访问权限:文件文件I/O编程编程v关闭文件关闭文件:关闭标准流文件的函数为关闭标准流文件的函数为fclose(),该函数将缓,该函数将缓冲区内的数据全部写入到文件中,并释放系统所提供的文冲区内的数据全部写入到文件中,并释放系统所提供的文件资源。件资源。文件文件I/O编程编程v在文件流被打开之后,可对文件流进行读写等操作,其中在文件流被打开之后,可对文件流进行读写等操作,其中读操作的函数为读操作的函数为fread() :文件文件I/O编程编程vfwrite()函数是用于对指定的文件流进行写操作。函数是用于对指定的文件流进行写操作。文件文件I/O编程编程v字符输入函数字符输入函数 v字符

24、输出函数字符输出函数 文件文件I/O编程编程v行输入函数行输入函数v行输出函数行输出函数文件文件I/O编程编程v格式化输入函数格式化输入函数文件文件I/O编程编程v格式化输出函数格式化输出函数进程控制编程进程控制编程v进程是指一个具有独立功能的程序在某个数据集合上的一进程是指一个具有独立功能的程序在某个数据集合上的一次动态执行过程,它是系统进行资源分配和调度的基本单次动态执行过程,它是系统进行资源分配和调度的基本单元。一次任务的运行可以并发激活多个进程,这些进程相元。一次任务的运行可以并发激活多个进程,这些进程相互合作来完成该任务的一个最终目标。互合作来完成该任务的一个最终目标。v进程和程序是

25、有本质区别的:进程和程序是有本质区别的:程序是静态的一段代码,是一些保存在非易失性存储程序是静态的一段代码,是一些保存在非易失性存储器的指令的有序集合,没有任何执行的概念;而进程器的指令的有序集合,没有任何执行的概念;而进程是一个动态的概念,它是程序执行的过程,包括了动是一个动态的概念,它是程序执行的过程,包括了动态创建、调度和消亡的整个过程,它是程序执行和资态创建、调度和消亡的整个过程,它是程序执行和资源管理的最小单位。源管理的最小单位。进程控制编程进程控制编程v进程状态转换关系:进程状态转换关系:进程控制编程进程控制编程v进程是通过进程控制块来描述的。进程控制块包含了进程进程是通过进程控制

26、块来描述的。进程控制块包含了进程的描述信息、控制信息以及资源信息,它是进程的一个静的描述信息、控制信息以及资源信息,它是进程的一个静态描述。进程控制块中每一项都是一个态描述。进程控制块中每一项都是一个task_struct结构。结构。 进程控制编程进程控制编程v在在Linux中,最主要的进程标识有进程号(中,最主要的进程标识有进程号(PID,Process Idenity Number)和它的父进程号()和它的父进程号(PPID,parent process ID)。其中)。其中PID惟一地标识一个进程。惟一地标识一个进程。PID和和PPID都是非零的正整数。都是非零的正整数。v在在Linux

27、中获得当前进程的中获得当前进程的PID和和PPID的系统调用函数为的系统调用函数为getpid()和和getppid(),通常程序获得当前进程的,通常程序获得当前进程的PID和和PPID之后,之后,可以将其写入日志文件以做备份。可以将其写入日志文件以做备份。 进程控制编程进程控制编程v进程的创建和执行进程的创建和执行v许多操作系统都提供的是产生进程的机制,也就是首先在许多操作系统都提供的是产生进程的机制,也就是首先在新的地址空间里创建进程、读入可执行文件,最后再开始新的地址空间里创建进程、读入可执行文件,最后再开始执行。执行。Linux中进程的创建很特别,它把上述步骤分解到中进程的创建很特别,

28、它把上述步骤分解到两个单独的函数中取执行:两个单独的函数中取执行:fork()和和exec函数族。首先,函数族。首先,fork()通过拷贝当前进程创建一个子进程,子进程与父进程的通过拷贝当前进程创建一个子进程,子进程与父进程的区别仅仅在于不同的区别仅仅在于不同的PID、PPID和某些资源及统计量。和某些资源及统计量。exec 函数族负责读取可执行文件并将其载入地址空间开始函数族负责读取可执行文件并将其载入地址空间开始运行。运行。进程控制编程进程控制编程v进程的终止进程的终止v进程终结也需要做很多繁琐的收尾工作,系统必须保证进进程终结也需要做很多繁琐的收尾工作,系统必须保证进程所占用的资源回收,

29、并通知父进程。程所占用的资源回收,并通知父进程。Linux首先把终止首先把终止的进程设置为僵尸状态,这个时候,进程无法投入运行了,的进程设置为僵尸状态,这个时候,进程无法投入运行了,它的存在只为父进程提供信息,申请死亡。父进程得到信它的存在只为父进程提供信息,申请死亡。父进程得到信息后,开始调用息后,开始调用wait函数族,最终赐死子进程,子进程占函数族,最终赐死子进程,子进程占用的所有资源被全部释放。用的所有资源被全部释放。进程控制编程进程控制编程v进程管理相关命令进程管理相关命令进程控制编程进程控制编程v在在Linux中创建一个新进程的方法是使用中创建一个新进程的方法是使用fork()函数

30、。函数。 vfork()函数用于从已存在的进程中创建一个新进程。新进函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而原进程称为父进程。使用程称为子进程,而原进程称为父进程。使用fork()函数得函数得到的子进程是父进程的一个复制品,它从父进程处继承了到的子进程是父进程的一个复制品,它从父进程处继承了整个进程的地址空间,包括进程上下文、代码段、进程堆整个进程的地址空间,包括进程上下文、代码段、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制和优先级、进程组号、当前工作目录、根目录

31、、资源限制和控制终端等,而子进程所独有的只有它的进程号、资源使控制终端等,而子进程所独有的只有它的进程号、资源使用和计时器等。用和计时器等。v因为子进程几乎是父进程的完全复制,所以父子两个进程因为子进程几乎是父进程的完全复制,所以父子两个进程会运行同一个程序。因此需要用一种方式来区分它们,并会运行同一个程序。因此需要用一种方式来区分它们,并使它们照此运行,否则,这两个进程不可能做不同的事。使它们照此运行,否则,这两个进程不可能做不同的事。进程控制编程进程控制编程v实际上是在父进程中执行实际上是在父进程中执行fork()函数时,父进程会复制出函数时,父进程会复制出一个子进程,而且父子进程的代码从

32、一个子进程,而且父子进程的代码从fork()函数的返回开函数的返回开始分别在两个地址空间中同时运行。从而两个进程分别获始分别在两个地址空间中同时运行。从而两个进程分别获得其所属得其所属fork()的返回值,其中在父进程中的返回值是子的返回值,其中在父进程中的返回值是子进程的进程号,而在子进程中返回进程的进程号,而在子进程中返回0。因此,可以通过返。因此,可以通过返回值来判定该进程是父进程还是子进程。回值来判定该进程是父进程还是子进程。v同时可以看出,使用同时可以看出,使用fork()函数的代价是很大的,它复制函数的代价是很大的,它复制了父进程中的代码段、数据段和堆栈段里的大部分内容,了父进程中

33、的代码段、数据段和堆栈段里的大部分内容,使得使得fork()函数的系统开销比较大,而且执行速度也不是函数的系统开销比较大,而且执行速度也不是很快。很快。进程控制编程进程控制编程vfork()函数语法函数语法进程控制编程进程控制编程vexec函数族就提供了一个在进程中启动另一个程序执行的函数族就提供了一个在进程中启动另一个程序执行的方法。它可根据指定的文件名或目录名找到可执行文件,方法。它可根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部执行完之后,原调用

34、进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是进制文件,也可以是Linux下任何可执行的脚本文件。下任何可执行的脚本文件。进程控制编程进程控制编程v使用使用exec函数族主要有两种情况函数族主要有两种情况 v当进程认为自己不能再为系统和用户做出任何贡献时,就当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用可以调用exec函数族中的任意一个函数让自己重生;函数族中的任意一个函数让自己重生;v 如果一个进程想执行另一个程序,那么它就可以调用如果一个进程想执行另一个程序,那么它就可以调用

35、fork()函数新建一个进程,然后调用函数新建一个进程,然后调用exec函数族中的任意一个函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新函数,这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。进程(这种情况非常普遍)。进程控制编程进程控制编程vexec函数族函数族语法及语法及对应位的含义对应位的含义进程控制编程进程控制编程v查找方式查找方式v表表中中的的前前四四个个函函数数的的查查找找方方式式都都是是完完整整的的文文件件目目录录路路径径,而而最最后后两两个个函函数数(以以p结结尾尾的的函函数数)可可以以只只给给出出文文件件名名,系系统统就会自动从环境变

36、量就会自动从环境变量“$PATH”所指出的路径中进行查找。所指出的路径中进行查找。v参数传递方式参数传递方式v两种方式:逐个列举、将所有参数整体构造指针数组传递两种方式:逐个列举、将所有参数整体构造指针数组传递v以函数名的第五位字母来区分的,字母为以函数名的第五位字母来区分的,字母为l(list)的表示逐个的表示逐个列举的方式,其语法为列举的方式,其语法为char *arg;字母为;字母为v(vertor)的表示的表示将所有参数整体构造指针数组传递,其语法为将所有参数整体构造指针数组传递,其语法为*const argv进程控制编程进程控制编程v环境变量环境变量vexec函函数数族族可可以以默默

37、认认系系统统的的环环境境变变量量,也也可可以以传传入入指指定定的的环环境境变变量量。这这里里,以以e(Enviromen)结结尾尾的的两两个个函函数数execle、execve就可以在就可以在envp中指定当前进程所使用的环境变量中指定当前进程所使用的环境变量进程控制编程进程控制编程vexec函数执行失败,常见原因:函数执行失败,常见原因:找不到文件或路径,此时找不到文件或路径,此时errno被设置为被设置为ENOENT; 数组数组argv和和envp忘记用忘记用NULL结束,此时结束,此时errno被设置被设置为为EFAULT; 没有对应可执行文件的运行权限,此时没有对应可执行文件的运行权限

38、,此时errno被设置为被设置为EACCES。进程控制编程进程控制编程vexit()和和_exit()exit()和和_exit()函数都是用来终止进程的。当程序执行到函数都是用来终止进程的。当程序执行到exit()或或_exit()时,进程会无条件地停止剩下的所有操作,时,进程会无条件地停止剩下的所有操作,清除包括各种数据结构,并终止本进程运行。清除包括各种数据结构,并终止本进程运行。 进程控制编程进程控制编程vexit()和和_exit()的执行过程的执行过程进程控制编程进程控制编程vexit()和和_exit()的区别的区别v_exit()函数的作用是直接使进程停止运行,清除其使用的函数

39、的作用是直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;内存空间,并销毁其在内核中的各种数据结构;vexit()函数则在这些基础上作了一些包装,在执行退出之前函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。加了若干道工序。vexit()函数与函数与_exit()函数最大的区别就在于函数最大的区别就在于exit()函数在终止函数在终止当前进程之前要检查该进程打开过哪些文件,把文件缓冲当前进程之前要检查该进程打开过哪些文件,把文件缓冲区中的内容写回文件,就是图中的区中的内容写回文件,就是图中的“清理清理I/O缓冲缓冲”一项。一项。进程控制编程进程控制编程vL

40、inux标准函数库中,有一种标准函数库中,有一种 “缓冲缓冲I/O(buffered I/O)”操作,其特征就是对应每一个打开的文件,在内存中都有操作,其特征就是对应每一个打开的文件,在内存中都有一片缓冲区。每次读文件时,会连续读出若干条记录,这一片缓冲区。每次读文件时,会连续读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区中读取;同样在下次读文件时就可以直接从内存的缓冲区中读取;同样,每次写文件的时候,也仅仅是写入内存中的缓冲区,样,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(如达到一定数量或遇到特定字符等)等满足了一定的条件(如达到一定数量或遇到特定字符等)

41、,再将缓冲区内容一次性写入文件。,再将缓冲区内容一次性写入文件。v这种技术大大增加了文件读写的速度,但也为编程带来了这种技术大大增加了文件读写的速度,但也为编程带来了一些麻烦。比如有些数据,认为已经被写入到文件中,实一些麻烦。比如有些数据,认为已经被写入到文件中,实际上因为没有满足特定的条件,它们还只是被保存在缓冲际上因为没有满足特定的条件,它们还只是被保存在缓冲区内,这时用区内,这时用_exit()函数直接将进程关闭,缓冲区中的数函数直接将进程关闭,缓冲区中的数据就会丢失。因此,若想保证数据的完整性,就一定要使据就会丢失。因此,若想保证数据的完整性,就一定要使用用exit()函数。函数。 进

42、程控制编程进程控制编程vexit()和和_exit函数语法函数语法进程控制编程进程控制编程vwait()函数是用于使父进程(也就是调用函数是用于使父进程(也就是调用wait()的进程)阻的进程)阻塞,直到一个子进程结束或者该进程接到了一个指定的信塞,直到一个子进程结束或者该进程接到了一个指定的信号为止。如果该父进程没有子进程或者他的子进程已经结号为止。如果该父进程没有子进程或者他的子进程已经结束,则束,则wait()就会立即返回。就会立即返回。vwaitpid()的作用和的作用和wait()一样,但它并不一定要等待第一一样,但它并不一定要等待第一个终止的子进程,它还有若干选项,如可提供一个非阻

43、塞个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的版本的wait()功能,也能支持作业控制。实际上功能,也能支持作业控制。实际上wait()函数函数只是只是waitpid()函数的一个特例,在函数的一个特例,在Linux内部实现内部实现wait()函函数时直接调用的就是数时直接调用的就是waitpid()函数函数进程控制编程进程控制编程vwait函数语法函数语法进程控制编程进程控制编程vwaitpid函数语法函数语法进程控制编程进程控制编程v守护进程,也就是通常所说的守护进程,也就是通常所说的Daemon进程,是进程,是Linux中的中的后台服务进程。它是一个生存期较长的进程,通常独立

44、于后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生控制终端并且周期性的执行某种任务或等待处理某些发生的事件。的事件。v守护进程常常在系统引导装入时启动,在系统关闭时才会守护进程常常在系统引导装入时启动,在系统关闭时才会终止。终止。vLinux系统有很多守护进程,大多数服务都是用守护进程系统有很多守护进程,大多数服务都是用守护进程实现的实现的 ,例如,作业规划进程例如,作业规划进程crond、打印进程、打印进程lqd等(这等(这里的结尾字母里的结尾字母d就是就是Daemon的意思)的意思)进程控制编程进程控制编程v在在Linux中,每一个系统与

45、用户进行交流的界面称为终端,中,每一个系统与用户进行交流的界面称为终端,每一个从此终端开始运行的进程都会依附于这个终端,这每一个从此终端开始运行的进程都会依附于这个终端,这个终端就称为这些进程的控制终端,当控制终端被关闭时,个终端就称为这些进程的控制终端,当控制终端被关闭时,相应的进程都会被自动关闭。相应的进程都会被自动关闭。v守护进程能够突破这种限制,它从被执行开始运转,直到守护进程能够突破这种限制,它从被执行开始运转,直到整个系统关闭才会退出。如果想让某个进程不因为用户或整个系统关闭才会退出。如果想让某个进程不因为用户或终端或其他的变化而受到影响,就必须把这个进程变成一终端或其他的变化而受

46、到影响,就必须把这个进程变成一个守护进程。个守护进程。进程控制编程进程控制编程v编写守护进程编写守护进程创建子进程,父进程退出创建子进程,父进程退出在子进程中创建新会话在子进程中创建新会话改变当前目录为根目录改变当前目录为根目录重设文件权限掩码重设文件权限掩码关闭文件描述符关闭文件描述符进程控制编程进程控制编程v创建子进程,父进程退出创建子进程,父进程退出这是编写守护进程的第一步。由于守护进程是脱离控制终端的,这是编写守护进程的第一步。由于守护进程是脱离控制终端的,因此,完成第一步后就会在因此,完成第一步后就会在shell终端里造成一种程序已经运行完终端里造成一种程序已经运行完毕的假象。之后的

47、所有工作都在子进程中完成,而用户在毕的假象。之后的所有工作都在子进程中完成,而用户在shell终终端里则可以执行其他的命令,从而在形式上做到了与控制终端的端里则可以执行其他的命令,从而在形式上做到了与控制终端的脱离。脱离。由于父进程已经先于子进程退出,会造成子进程没有父进程,从由于父进程已经先于子进程退出,会造成子进程没有父进程,从而变成一个孤儿进程。在而变成一个孤儿进程。在Linux中,每当系统发现一个孤儿进程,中,每当系统发现一个孤儿进程,就会自动由就会自动由1号进程(也就是号进程(也就是init进程)收养它,这样,原先的子进程)收养它,这样,原先的子进程就会变成进程就会变成init进程的

48、子进程了。实例:进程的子进程了。实例:pid = fork();if (pid 0) exit(0); /*父进程退出父进程退出*/ 进程控制编程进程控制编程v在子进程中创建新会话在子进程中创建新会话进程组进程组进程组是一个或多个进程的集合。进程组由进程组进程组是一个或多个进程的集合。进程组由进程组ID来惟一标来惟一标识。除了进程号(识。除了进程号(PID)之外,进程组)之外,进程组ID也是一个进程的必备也是一个进程的必备属性。属性。每个进程组都有一个组长进程,其组长进程的进程号等于进程每个进程组都有一个组长进程,其组长进程的进程号等于进程组组ID。且该进程。且该进程ID不会因组长进程的退出而

49、受到影响。不会因组长进程的退出而受到影响。 会话期会话期会话组是一个或多个进程组的集合。通常,一个会话开始于用会话组是一个或多个进程组的集合。通常,一个会话开始于用户登录,终止于用户退出,在此期间该用户运行的所有进程都户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期属于这个会话期 进程控制编程进程控制编程v在子进程中创建新会话在子进程中创建新会话setsid()函数作用函数作用setsid()函数用于创建一个新的会话,并担任该会话组函数用于创建一个新的会话,并担任该会话组的组长。调用的组长。调用setsid()有下面的有下面的3个作用。个作用。让进程摆脱原会话的控制。让进程

50、摆脱原会话的控制。让进程摆脱原进程组的控制。让进程摆脱原进程组的控制。让进程摆脱原控制终端的控制。让进程摆脱原控制终端的控制。setsid()函数格式:函数格式:进程控制编程进程控制编程v改变当前目录为根目录改变当前目录为根目录通常的做法是让通常的做法是让“/”作为守护进程的当前工作目录作为守护进程的当前工作目录 。使用使用fork创建的子进程继承了父进程的当前工作目录。创建的子进程继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统是由于在进程运行过程中,当前目录所在的文件系统是不能卸载的,这对以后的使用会造成诸多的麻烦不能卸载的,这对以后的使用会造成诸多的麻烦(比如比如

51、进入单用户模式进入单用户模式)进程控制编程进程控制编程v重设文件权限掩码重设文件权限掩码文件权限掩码是指屏蔽掉文件权限中的对应位。由于文件权限掩码是指屏蔽掉文件权限中的对应位。由于使用使用fork新建的子进程继承了父进程的文件权限掩码,新建的子进程继承了父进程的文件权限掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件权限掩码设置为把文件权限掩码设置为0,可以大大增加该守护进程的,可以大大增加该守护进程的灵活性。设置文件权限掩码的函数是灵活性。设置文件权限掩码的函数是umask通常的使用方法为通常的使用方法为umask(0)进程控制编程进程

52、控制编程v关闭文件描述符关闭文件描述符同文件权限掩码一样,用同文件权限掩码一样,用fork新建的子进程会从父进程新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系可能永远不会被守护进程读或写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸下统资源,而且可能导致所在的文件系统无法卸下 在上面的第二步后,守护进程已经与所属的控制终端在上面的第二步后,守护进程已经与所属的控制终端失去了联系。因此从终端输入的字符不可能达到守护失去了联系。因此从终端输入的字符不可能达到守护进程,守护进

53、程中用常规的方法进程,守护进程中用常规的方法(如如printf)输出的字符输出的字符也不可能在终端上显示出来。所以,文件描述符为也不可能在终端上显示出来。所以,文件描述符为0、1和和2的三个文件的三个文件(常说的输入、输出和报错这三个文件常说的输入、输出和报错这三个文件)已经失去了存在的价值,也应被关闭。已经失去了存在的价值,也应被关闭。实例:实例: for(i=0;iMAXFILE;i+) close(i); 进程控制编程进程控制编程v读者在前面编写守护进程的具体调试过程中会发现,由于读者在前面编写守护进程的具体调试过程中会发现,由于守护进程完全脱离了控制终端,因此,不能像其他普通进守护进程

54、完全脱离了控制终端,因此,不能像其他普通进程一样将错误信息输出到控制终端来通知程序员。守护进程一样将错误信息输出到控制终端来通知程序员。守护进程的一种通用的办法是使用程的一种通用的办法是使用syslog服务,将程序中的出错服务,将程序中的出错信息输入到系统日志文件中,从而可以直观地看到程序的信息输入到系统日志文件中,从而可以直观地看到程序的问题所在。问题所在。 进程控制编程进程控制编程v守护进程出错处理守护进程出错处理syslog是是Linux中的系统日志管理服务,通过守护进程中的系统日志管理服务,通过守护进程syslogd来维护。该守护进程在启动时会读一个配置文来维护。该守护进程在启动时会读

55、一个配置文件件/etc/syslog.conf。该文件决定了不同种类的消息会发。该文件决定了不同种类的消息会发送向何处。例如紧急消息可被送向系统管理员并在控送向何处。例如紧急消息可被送向系统管理员并在控制台上显示,而警告消息则可被记录到一个文件中。制台上显示,而警告消息则可被记录到一个文件中。该机制提供了该机制提供了3个个syslog相关函数,分别为相关函数,分别为openlog()、syslog()和和closelog()。openlog()函数用于打开系统日志服务的函数用于打开系统日志服务的一个连接;一个连接;syslog()函数是用于向日志文件中写入消息,函数是用于向日志文件中写入消息,

56、在这里可以规定消息的优先级、消息输出格式等;在这里可以规定消息的优先级、消息输出格式等;closelog()函数是用于关闭系统日志服务连接。函数是用于关闭系统日志服务连接。进程控制编程进程控制编程vsyslog相关函数格式相关函数格式 所需头文件所需头文件#include 函数原型函数原型void openlog (char *ident, int option , int facility)函数传入值函数传入值ident要向每个消息加入的字符串,通常为程序的名称要向每个消息加入的字符串,通常为程序的名称optionLOG_CONS:如果消息无法送到系统日志服务,则直接输出到系统控制终端:如果

57、消息无法送到系统日志服务,则直接输出到系统控制终端LOG_NDELAY:立即打开系统日志服务的连接。在正常情况下,直接发送到:立即打开系统日志服务的连接。在正常情况下,直接发送到第一条消息时才打开连接第一条消息时才打开连接LOG_PERROR:将消息也同时送到:将消息也同时送到stderr上上LOG_PID:在每条消息中包含进程的:在每条消息中包含进程的PID函数传入值函数传入值Facility:指定程序指定程序发送消息发送消息类型类型LOG_AUTHPRIV:安全:安全/授权讯息授权讯息LOG_CRON:时间守护进程(:时间守护进程(cron及及at)LOG_DAEMON:其他系统守护进程:

58、其他系统守护进程LOG_KERN:内核信息:内核信息LOG_LOCAL07:保留:保留LOG_LPR:行打印机子系统:行打印机子系统LOG_MAIL:邮件子系统:邮件子系统LOG_NEWS:新闻子系统:新闻子系统LOG_SYSLOG:syslogd内部所产生的信息内部所产生的信息LOG_USER:一般使用者等级讯息:一般使用者等级讯息LOG_UUCP:UUCP子系统子系统进程控制编程进程控制编程vsyslog相关函数格式相关函数格式所需头文件所需头文件#include 函数原型函数原型void syslog(int priority, char *format, .)函数传入值函数传入值pri

59、ority:指定消息指定消息重要性重要性LOG_EMERG:系统无法使用:系统无法使用LOG_ALERT:需要立即采取措施:需要立即采取措施LOG_CRIT:有重要情况发生:有重要情况发生LOG_ERR:有错误发生:有错误发生LOG_WARNING:有警告发生:有警告发生LOG_NOTICE:正常情况,但也是重要情况:正常情况,但也是重要情况LOG_INFO:信息消息:信息消息LOG_DEBUG:调试信息:调试信息format以字符串指针的形式表示输出的格式,类似以字符串指针的形式表示输出的格式,类似printf的格式的格式所需头文件所需头文件#include 函数原型函数原型void clo

60、selog(void)进程间的通信和同步进程间的通信和同步 vLinux下的进程通信手段基本上是从下的进程通信手段基本上是从Unix平台上的进程通平台上的进程通信手段继承而来的信手段继承而来的v集合集合System V IPC(贝尔实验室贝尔实验室)和和socket的进程间通信机的进程间通信机制制(BSD)的优势的优势Unix进程间通信方式包括管道、进程间通信方式包括管道、FIFO以及信号。以及信号。System V进程间通信包括进程间通信包括System V消息队列、消息队列、System V信号量以及信号量以及System V共享内存区。共享内存区。 Posix 进程间通信包括进程间通信包

61、括Posix消息队列、消息队列、Posix信号量以信号量以及及Posix共享内存区共享内存区进程间的通信和同步进程间的通信和同步进程间的通信和同步进程间的通信和同步v常用的进程间通信机制常用的进程间通信机制(1)管道()管道(Pipe)及有名管道()及有名管道(named pipe):管道可用于具):管道可用于具有有亲缘关系进程间的通信亲缘关系进程间的通信,有名管道,除具有管道所具有的功能,有名管道,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。外,它还允许无亲缘关系进程间的通信。(2)信号()信号(Signal):信号是在软件层次上):信号是在软件层次上对中断机制的一种模对中断机

62、制的一种模拟拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是个进程收到一个信号与处理器收到一个中断请求效果上可以说是一样的。一样的。(3)消息队列()消息队列(Messge Queue):消息队列是消息的链接表,):消息队列是消息的链接表,包括包括Posix消息队列消息队列SystemV消息队列。它消息队列。它克服了前两种通信方式克服了前两种通信方式中信息量有限的缺点中信息量有限的缺点,具有写权限的进程可以按照一定的规则向,具有写权限的进程可以按照一定的规则向消息队列中添加新消

63、息;对消息队列有读权限的进程则可以从消消息队列中添加新消息;对消息队列有读权限的进程则可以从消息队列中读取消息。息队列中读取消息。进程间的通信和同步进程间的通信和同步v常用的进程间通信机制常用的进程间通信机制(4)共享内存()共享内存(Shared memory):可以说这是):可以说这是最有效的进程最有效的进程间通信方式间通信方式。它使得多个进程可以访问同一块内存空间,不同进。它使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种程可以及时看到对方进程中对共享内存中数据的更新。这种通信通信方式需要依靠某种同步机制,如互斥锁和信号量方式需要依靠某种同步

64、机制,如互斥锁和信号量等。等。(5)信号量()信号量(Semaphore):主要作为进程之间以及同一进程):主要作为进程之间以及同一进程的不同线程之间的的不同线程之间的同步和互斥手段同步和互斥手段。(6)套接字()套接字(Socket):这是一种更为一般的进程间通信机制,):这是一种更为一般的进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。它可用于网络中不同机器之间的进程间通信,应用非常广泛。进程间的通信和同步进程间的通信和同步vLinux的管道主要包括两种:无名管道和有名管道。的管道主要包括两种:无名管道和有名管道。v无名管道特点无名管道特点它只能用于具有亲缘关系的进程

65、之间的通信(也就是它只能用于具有亲缘关系的进程之间的通信(也就是父子进程或者兄弟进程之间)。父子进程或者兄弟进程之间)。它是一个它是一个半双工通信模式半双工通信模式,具有固定的读端和写端。,具有固定的读端和写端。管道也可以看成是一种特殊的文件,对于它的读写也管道也可以看成是一种特殊的文件,对于它的读写也可以使用普通的可以使用普通的read()、write()等函数。但是它不是普等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在通的文件,并不属于其他任何文件系统,并且只存在于内存中于内存中 进程间的通信和同步进程间的通信和同步vLinux的管道主要包括两种:无名管道和有名管道。的

66、管道主要包括两种:无名管道和有名管道。v有名管道特点有名管道特点它可以使互不相关的两个进程实现彼此通信。它可以使互不相关的两个进程实现彼此通信。该管道可以通过路径名来指出,并且在文件系统中是该管道可以通过路径名来指出,并且在文件系统中是可见的。在建立了管道之后,两个进程就可以把它当可见的。在建立了管道之后,两个进程就可以把它当作普通文件一样进行读写操作,使用非常方便。作普通文件一样进行读写操作,使用非常方便。FIFO严格地遵循先进先出规则,对管道及严格地遵循先进先出规则,对管道及FIFO的读总的读总是从开始处返回数据,对它们的写则把数据添加到末是从开始处返回数据,对它们的写则把数据添加到末尾,

67、它们不支持如尾,它们不支持如lseek()等文件定位操作。等文件定位操作。进程间的通信和同步进程间的通信和同步v无名管道创建和关闭无名管道创建和关闭管道是基于文件描述符的通信方式,当一个管道建立管道是基于文件描述符的通信方式,当一个管道建立时,它会创建两个文件描述符时,它会创建两个文件描述符fds0和和fds1,其中,其中fds0固定用于读管道,而固定用于读管道,而fd1固定用于写管道,这样固定用于写管道,这样就构成了一个半双工的通道。就构成了一个半双工的通道。 管道关闭时只需将这两个文件描述符关闭即可,可使管道关闭时只需将这两个文件描述符关闭即可,可使用普通的用普通的close()函数逐个关

68、闭各个文件描述符。函数逐个关闭各个文件描述符。进程间的通信和同步进程间的通信和同步vpipe()创建管道可以通过调用创建管道可以通过调用pipe()来实现来实现vpipe()语法:语法:进程间的通信和同步进程间的通信和同步v父子进程管道的文件描述符对应关系父子进程管道的文件描述符对应关系进程间的通信和同步进程间的通信和同步v无名管道读写注意点:无名管道读写注意点:只有在管道的读端存在时,向管道写入数据才有意义。否则,向只有在管道的读端存在时,向管道写入数据才有意义。否则,向管道写入数据的进程将收到内核传来的管道写入数据的进程将收到内核传来的SIGPIPE信号(通常为信号(通常为Broken p

69、ipe错误)。错误)。向管道写入数据时,向管道写入数据时,Linux将不保证写入的原子性,管道缓冲区一将不保证写入的原子性,管道缓冲区一有空闲区域,写进程就会试图向管道写入数据。如果读进程不读有空闲区域,写进程就会试图向管道写入数据。如果读进程不读取管道缓冲区中的数据,那么写操作将会一直阻塞。取管道缓冲区中的数据,那么写操作将会一直阻塞。父子进程在运行时,它们的先后次序并不能保证,因此,在为了父子进程在运行时,它们的先后次序并不能保证,因此,在为了保证父子进程已经关闭了相应的文件描述符,可在两个进程中调保证父子进程已经关闭了相应的文件描述符,可在两个进程中调用用sleep()函数,当然这种调用

70、不是很好的解决方法,在后面可采函数,当然这种调用不是很好的解决方法,在后面可采用进程之间的同步与互斥机制用进程之间的同步与互斥机制进程间的通信和同步进程间的通信和同步v标准流管道函数说明标准流管道函数说明与与Linux的文件操作中有基于文件流的标准的文件操作中有基于文件流的标准I/O操作一样,管道的操作一样,管道的操作也支持基于文件流的模式。这种基于文件流的管道主要是用操作也支持基于文件流的模式。这种基于文件流的管道主要是用来创建一个连接到另一个进程的管道,这里的来创建一个连接到另一个进程的管道,这里的“另一个进程另一个进程”也也就是一个可以进行一定操作的可执行文件就是一个可以进行一定操作的可

71、执行文件 。标准流管道就将一系列的创建过程合并到一个函数标准流管道就将一系列的创建过程合并到一个函数popen()中完成。中完成。它所完成的工作有以下几步。它所完成的工作有以下几步。创建一个管道。创建一个管道。fork()一个子进程。一个子进程。在父子进程中关闭不需要的文件描述符。在父子进程中关闭不需要的文件描述符。执行执行exec函数族调用。函数族调用。执行函数中所指定的命令执行函数中所指定的命令进程间的通信和同步进程间的通信和同步vpopen和和 pclose函数格式函数格式进程间的通信和同步进程间的通信和同步v有名管道有名管道(FIFO)通过通过mkfifo()创建有名管道创建有名管道,

72、可以指定管道的路径和打开可以指定管道的路径和打开的模式。的模式。 mkfifo()函数语法:函数语法:进程间的通信和同步进程间的通信和同步v有名管道有名管道(FIFO)FIFO相关出错信息相关出错信息进程间的通信和同步进程间的通信和同步v有名管道有名管道FIFO读写读写v对于读进程对于读进程若该管道是阻塞打开,且当前若该管道是阻塞打开,且当前FIFO内没有数据,则对读进程而言内没有数据,则对读进程而言将一直阻塞到有数据写入。将一直阻塞到有数据写入。若该管道是非阻塞打开,则不论若该管道是非阻塞打开,则不论FIFO内是否有数据,读进程都会内是否有数据,读进程都会立即执行读操作。即如果立即执行读操作

73、。即如果FIFO内没有数据,则读函数将立刻返回内没有数据,则读函数将立刻返回0。v对于写进程对于写进程若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。若该管道是阻塞打开,则写操作将一直阻塞到数据可以被写入。若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分若该管道是非阻塞打开而不能写入全部数据,则读操作进行部分写入或者调用失败。写入或者调用失败。进程间的通信和同步进程间的通信和同步v信号是在软件层次上对中断机制的一种模拟,是一种异步信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式通信方式v信号可以直接进行用户空间进程和内核进程之间的交互,信号可以直接进行用户空间进程和内

74、核进程之间的交互,内核进程也可以利用它来通知用户空间进程发生了哪些系内核进程也可以利用它来通知用户空间进程发生了哪些系统事件。它可以在任何时候发给某一进程,而无需知道该统事件。它可以在任何时候发给某一进程,而无需知道该进程的状态。进程的状态。v如果该进程当前并未处于执行态,则该信号就由内核保存如果该进程当前并未处于执行态,则该信号就由内核保存起来,直到该进程恢复执行再传递给它;如果一个信号被起来,直到该进程恢复执行再传递给它;如果一个信号被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被进程设置为阻塞,则该信号的传递被延迟,直到其阻塞被取消时才被传递给进程。取消时才被传递给进程。进程间的通信

75、和同步进程间的通信和同步v信号是进程间通信机制中惟一的异步通信机制,可以看作信号是进程间通信机制中惟一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过号机制经过POSIX实时扩展后,功能更加强大,除了基本实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。通知功能外,还可以传递附加信息。v信号事件的发生有两个来源:硬件来源(比如我们按下了信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其他硬件故障);软件来源,最常用发送信号的键盘或者其他硬件故障);软件来源,最常用发送信号的系统函数有

76、系统函数有kill()、raise()、alarm()、setitimer()和和sigqueue()等,软件来源还包括一些非法运算等操作。等,软件来源还包括一些非法运算等操作。进程间的通信和同步进程间的通信和同步v进程可以通过进程可以通过3种方式来响应一个信号种方式来响应一个信号忽略信号,即对信号不做任何处理,其中,有两个信忽略信号,即对信号不做任何处理,其中,有两个信号不能忽略:号不能忽略:SIGKILL及及SIGSTOP。捕捉信号,定义信号处理函数,当信号发生时,执行捕捉信号,定义信号处理函数,当信号发生时,执行相应的处理函数。相应的处理函数。执行缺省操作,执行缺省操作,Linux对每种

77、信号都规定了默认操作对每种信号都规定了默认操作 。进程间的通信和同步进程间的通信和同步v信号缺省操作信号缺省操作进程间的通信和同步进程间的通信和同步v信号发送:信号发送:kill()和和raise()vkill()函数同函数同kill系统命令一样,可以发送信号给进程或进系统命令一样,可以发送信号给进程或进程组程组,它不仅可以中止进程(实际上发出它不仅可以中止进程(实际上发出SIGKILL信号),信号),也可以向进程发送其他信号。也可以向进程发送其他信号。vkill()函数语法:函数语法:进程间的通信和同步进程间的通信和同步v信号捕捉:信号捕捉:alarm()、pause()valarm()也称

78、为闹钟函数,它可以在进程中设置一个定时器,当定时器也称为闹钟函数,它可以在进程中设置一个定时器,当定时器指定的时间到时,它就向进程发送指定的时间到时,它就向进程发送SIGALARM信号信号 。vpause()函数是用于将调用进程挂起直至捕捉到信号为止。这个函数很函数是用于将调用进程挂起直至捕捉到信号为止。这个函数很常用,通常可以用于判断信号是否已到。常用,通常可以用于判断信号是否已到。进程间的通信和同步进程间的通信和同步v信号的处理:信号的处理:signal、sigactionv使用使用signal()处理信号时,只需要指出要处理的信号和处理处理信号时,只需要指出要处理的信号和处理函数即可。它

79、主要是用于前函数即可。它主要是用于前32种非实时信号的处理,不支种非实时信号的处理,不支持信号传递信息,但是由于使用简单、易于理解,因此也持信号传递信息,但是由于使用简单、易于理解,因此也受到很多程序员的欢迎受到很多程序员的欢迎 。vsignal()函数的语法函数的语法进程间的通信和同步进程间的通信和同步v信号的处理:信号的处理:signal、sigactionvsigaction() 函数相对于函数相对于signal()更加健壮,推荐使用这个更加健壮,推荐使用这个进程间的通信和同步进程间的通信和同步v信号的处理:信号的处理:signal、sigactionvsigaction()函数中第函数

80、中第2个和第个和第3个参数用到的个参数用到的sigaction结构结构struct sigaction void (*sa_handler)(int signo); sigset_t sa_mask; int sa_flags; void (*sa_restore)(void); 进程间的通信和同步进程间的通信和同步vsa_handler是一个函数指针,指定信号处理函数,这里除是一个函数指针,指定信号处理函数,这里除可以是用户自定义的处理函数外,还可以为可以是用户自定义的处理函数外,还可以为SIG_DFL(采(采用缺省的处理方式)或用缺省的处理方式)或SIG_IGN(忽略信号)。它的处理(忽略

81、信号)。它的处理函数只有一个参数,即信号值。函数只有一个参数,即信号值。vsa_mask是一个信号集,它可以指定在信号处理程序执行是一个信号集,它可以指定在信号处理程序执行过程中哪些信号应当被屏蔽,在调用信号捕获函数之前,过程中哪些信号应当被屏蔽,在调用信号捕获函数之前,该信号集要加入到信号的信号屏蔽字中。该信号集要加入到信号的信号屏蔽字中。vsa_flags中包含了许多标志位,是对信号进行处理的各个中包含了许多标志位,是对信号进行处理的各个选择项选择项 进程间的通信和同步进程间的通信和同步v信号发送和捕捉信号发送和捕捉v使用信号集函数组处理信号时涉及一系列的函数,这些函数按照调用使用信号集函

82、数组处理信号时涉及一系列的函数,这些函数按照调用的先后次序可分为以下几大功能模块:创建信号集合、注册信号处理的先后次序可分为以下几大功能模块:创建信号集合、注册信号处理函数以及检测信号。函数以及检测信号。v其中,创建信号集合主要用于处理用户感兴趣的一些信号,其函数包其中,创建信号集合主要用于处理用户感兴趣的一些信号,其函数包括以下几个。括以下几个。sigemptyset():将信号集合初始化为空。:将信号集合初始化为空。sigfillset():将信号集合初始化为包含所有已定义的信号的集合。:将信号集合初始化为包含所有已定义的信号的集合。sigaddset():将指定信号加入到信号集合中去。:

83、将指定信号加入到信号集合中去。sigdelset():将指定信号从信号集合中删去。:将指定信号从信号集合中删去。sigismember():查询指定信号是否在信号集合之中。:查询指定信号是否在信号集合之中。进程间的通信和同步进程间的通信和同步v信号发送和捕捉信号发送和捕捉v总之,在处理信号时,一般遵循如下图所示的操作流程总之,在处理信号时,一般遵循如下图所示的操作流程进程间的通信和同步进程间的通信和同步v信号量是用来解决进程之间的同步与互斥问题的一种进程之间通信机信号量是用来解决进程之间的同步与互斥问题的一种进程之间通信机制,包括一个称为信号量的变量和在该信号量下等待资源的进程等待制,包括一个

84、称为信号量的变量和在该信号量下等待资源的进程等待队列,以及对信号量进行的两个原子操作(队列,以及对信号量进行的两个原子操作(PV操作)。其中信号量对操作)。其中信号量对应于某一种资源,取一个非负的整型值。信号量值指的是当前可用的应于某一种资源,取一个非负的整型值。信号量值指的是当前可用的该资源的数量,若它等于该资源的数量,若它等于0则意味着目前没有可用的资源。则意味着目前没有可用的资源。vPV原子操作的具体定义为:原子操作的具体定义为:P操作:如果有可用的资源(信号量值操作:如果有可用的资源(信号量值0),则占用一个资源(给),则占用一个资源(给信号量值减去一,进入临界区代码)信号量值减去一,

85、进入临界区代码);如果没有可用的资源(信号如果没有可用的资源(信号量值等于量值等于0),则被阻塞到,直到系统将资源分配给该进程(进入),则被阻塞到,直到系统将资源分配给该进程(进入等待队列,一直等到资源轮到该进程)。等待队列,一直等到资源轮到该进程)。V操作:如果在该信号量的等待队列中有进程在等待资源,则唤醒操作:如果在该信号量的等待队列中有进程在等待资源,则唤醒一个阻塞进程。如果没有进程等待它,则释放一个资源(给信号一个阻塞进程。如果没有进程等待它,则释放一个资源(给信号量值加一)。量值加一)。进程间的通信和同步进程间的通信和同步v信号量概述信号量概述常见的使用信号量访问临界区的伪代码所下所

86、示:常见的使用信号量访问临界区的伪代码所下所示:/* 设设R为某种资源,为某种资源,S为资源为资源R的信号量的信号量*/INIT_VAL(S);/* 对信号量对信号量S进行初始化进行初始化 */非临界区非临界区;P(S);/* 进行进行P操作操作 */临界区(使用资源临界区(使用资源R); /* 只有有限个(通常只有一个)进程被允许进入该区只有有限个(通常只有一个)进程被允许进入该区*/V(S); /* 进行进行V操作操作 */非临界区非临界区;进程间的通信和同步进程间的通信和同步v信号量编程信号量编程:v第一步:创建信号量或获得在系统已存在的信号量,此时需要调用第一步:创建信号量或获得在系统

87、已存在的信号量,此时需要调用semget()函数。不同进程通过使用同一个信号量键值来获得同一个信号量。函数。不同进程通过使用同一个信号量键值来获得同一个信号量。v第二步:初始化信号量,此时使用第二步:初始化信号量,此时使用semctl()函数的函数的SETVAL操作。当使操作。当使用二维信号量时,通常将信号量初始化为用二维信号量时,通常将信号量初始化为1。v第三步:进行信号量的第三步:进行信号量的PV操作,此时调用操作,此时调用semop()函数。这一步是实函数。这一步是实现进程之间的同步和互斥的核心工作部分。现进程之间的同步和互斥的核心工作部分。v第四步:如果不需要信号量,则从系统中删除它,

88、此时使用第四步:如果不需要信号量,则从系统中删除它,此时使用semclt()函函数的数的IPC_RMID操作。此时需要注意,在程序中不应该出现对已经被操作。此时需要注意,在程序中不应该出现对已经被删除的信号量的操作。删除的信号量的操作。进程间的通信和同步进程间的通信和同步vsemget()函数语法函数语法进程间的通信和同步进程间的通信和同步vsemctl()函数语法函数语法进程间的通信和同步进程间的通信和同步vsemop()函数语法函数语法进程间的通信和同步进程间的通信和同步v共享内存是一种最为高效的进程间通信方式,进程可以直共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需

89、要任何数据的拷贝接读写内存,而不需要任何数据的拷贝v为了在多个进程间交换信息,内核专门留出了一块内存区,为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己私有地址空间可以由需要访问的进程将其映射到自己私有地址空间v进程就可以直接读写这一内存区而不需要进行数据的拷贝,进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。从而大大提高的效率。v由于多个进程共享一段内存,因此也需要依靠某种同步机由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等制,如互斥锁和信号量等进程间的通信和同步进程间的通信和同步v共享内存原理示意图共享

90、内存原理示意图进程间的通信和同步进程间的通信和同步v共享内存实现的步骤:共享内存实现的步骤:v创建共享内存,这里用到的函数是创建共享内存,这里用到的函数是shmget,也就是从内存,也就是从内存中获得一段共享内存区域中获得一段共享内存区域v映射共享内存,也就是把这段创建的共享内存映射到具体映射共享内存,也就是把这段创建的共享内存映射到具体的进程空间中去,这里使用的函数是的进程空间中去,这里使用的函数是shmatv到这里,就可以使用这段共享内存了,也就是可以使用不到这里,就可以使用这段共享内存了,也就是可以使用不带缓冲的带缓冲的I/O读写命令对其进行操作读写命令对其进行操作v撤销映射的操作,其函

91、数为撤销映射的操作,其函数为shmdt 进程间的通信和同步进程间的通信和同步vshmget函数语法函数语法进程间的通信和同步进程间的通信和同步vshmat函数语法函数语法进程间的通信和同步进程间的通信和同步vshmdt函数语法函数语法进程间的通信和同步进程间的通信和同步v消息队列就是一些消息的列表。用户可以在消息队列中添消息队列就是一些消息的列表。用户可以在消息队列中添加消息和读取消息等。从这点上看,消息队列具有一定的加消息和读取消息等。从这点上看,消息队列具有一定的FIFO特性,但是它可以实现消息的随机查询,比特性,但是它可以实现消息的随机查询,比FIFO具具有更大的优势。同时,这些消息又是

92、存在于内核中的,由有更大的优势。同时,这些消息又是存在于内核中的,由“队列队列ID”来标识。来标识。进程间的通信和同步进程间的通信和同步v消消息息队队列列的的实实现现包包括括创创建建或或打打开开消消息息队队列列、添添加加消消息息、读读取消息和控制消息队列这四种操作取消息和控制消息队列这四种操作v创创建建或或打打开开消消息息队队列列使使用用的的函函数数是是msgget,这这里里创创建建的的消消息队列的数量会受到系统消息队列数量的限制息队列的数量会受到系统消息队列数量的限制v添添加加消消息息使使用用的的函函数数是是msgsnd函函数数,它它把把消消息息添添加加到到已已打打开的消息队列末尾开的消息队

93、列末尾v读读取取消消息息使使用用的的函函数数是是msgrcv,它它把把消消息息从从消消息息队队列列中中取取走,与走,与FIFO不同的是,这里可以指定取走某一条消息不同的是,这里可以指定取走某一条消息v控制消息队列使用的函数是控制消息队列使用的函数是msgctl,它可完成多项功能,它可完成多项功能进程间的通信和同步进程间的通信和同步vmsgget函数语法:函数语法:进程间的通信和同步进程间的通信和同步vmsgsnd函数语法函数语法进程间的通信和同步进程间的通信和同步vmsgrcv函数语法函数语法进程间的通信和同步进程间的通信和同步vmsgctl函数语法函数语法多线程编程多线程编程 v创建线程实际

94、上就是确定调用该线程函数的入口点,这里通常使用的创建线程实际上就是确定调用该线程函数的入口点,这里通常使用的函数是函数是pthread_create()。 v在线程创建之后,就开始运行相关的线程函数,在该函数运行完之后,在线程创建之后,就开始运行相关的线程函数,在该函数运行完之后,该线程也就退出了,这也是线程退出的一种方法。另一种退出线程的该线程也就退出了,这也是线程退出的一种方法。另一种退出线程的方法是使用函数方法是使用函数pthread_exit(),这是线程的主动行为。,这是线程的主动行为。 vpthread_join()可以用于将当前线程挂起来等待线程的结束。这个函数可以用于将当前线程

95、挂起来等待线程的结束。这个函数是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结是一个线程阻塞的函数,调用它的函数将一直等待到被等待的线程结束为止,当函数返回时,被等待线程的资源就被收回。束为止,当函数返回时,被等待线程的资源就被收回。 vpthread_cancel() 向其他线程发送终止信号,但在被取消的线程的内向其他线程发送终止信号,但在被取消的线程的内部需要调用部需要调用pthread_setcancel()函数和函数和pthread_setcanceltype()函数设函数设置自己的取消状态。置自己的取消状态。多线程编程多线程编程vphtread_create()函数语法函

96、数语法 vphtread_exit()函数语法函数语法多线程编程多线程编程vphtread_join()函数语法:函数语法:vphtread_cancel()函数语法:函数语法:多线程编程多线程编程v互斥锁线程控制互斥锁线程控制互斥锁是用一种简单的加锁方法来控制对共享资源的互斥锁是用一种简单的加锁方法来控制对共享资源的原子操作。原子操作。 互斥锁只有两种状态,也就是上锁和解锁,可以把互互斥锁只有两种状态,也就是上锁和解锁,可以把互斥锁看作某种意义上的全局变量。斥锁看作某种意义上的全局变量。 在同一时刻只能有一个线程掌握某个互斥锁,拥有上在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程

97、能够对共享资源进行操作。若其他线程锁状态的线程能够对共享资源进行操作。若其他线程希望上锁一个已经被上锁的互斥锁,则该线程就会挂希望上锁一个已经被上锁的互斥锁,则该线程就会挂起,直到上锁的线程释放掉互斥锁为止。起,直到上锁的线程释放掉互斥锁为止。多线程编程多线程编程v互斥锁机制主要包括下面的基本函数。互斥锁机制主要包括下面的基本函数。 互斥锁初始化:互斥锁初始化:pthread_mutex_init() 互斥锁上锁:互斥锁上锁:pthread_mutex_lock() 互斥锁判断上锁:互斥锁判断上锁:pthread_mutex_trylock() 互斥锁接锁:互斥锁接锁:pthread_mute

98、x_unlock() 消除互斥锁:消除互斥锁:pthread_mutex_destroy()v互斥锁可以分为快速互斥锁、递归互斥锁和检错互斥锁。这三种锁的互斥锁可以分为快速互斥锁、递归互斥锁和检错互斥锁。这三种锁的区别主要在于其他未占有互斥锁的线程在希望得到互斥锁时是否需要区别主要在于其他未占有互斥锁的线程在希望得到互斥锁时是否需要阻塞等待。快速锁是指调用线程会阻塞直至拥有互斥锁的线程解锁为阻塞等待。快速锁是指调用线程会阻塞直至拥有互斥锁的线程解锁为止。递归互斥锁能够成功地返回,并且增加调用线程在互斥上加锁的止。递归互斥锁能够成功地返回,并且增加调用线程在互斥上加锁的次数,而检错互斥锁则为快速

99、互斥锁的非阻塞版本,它会立即返回并次数,而检错互斥锁则为快速互斥锁的非阻塞版本,它会立即返回并返回一个错误信息。默认属性为快速互斥锁。返回一个错误信息。默认属性为快速互斥锁。 多线程编程多线程编程vpthread_mutex_init()函数语法函数语法多线程编程多线程编程vpthread_mutex_lock()函数语法函数语法多线程编程多线程编程v信号量线程控制信号量线程控制信号量也就是操作系统中所用到的信号量也就是操作系统中所用到的PV原子操作,它广原子操作,它广泛用于进程或线程间的同步与互斥。信号量本质上是泛用于进程或线程间的同步与互斥。信号量本质上是一个非负的整数计数器,它被用来控制

100、对公共资源的一个非负的整数计数器,它被用来控制对公共资源的访问。访问。 PV原子操作是对整数计数器信号量原子操作是对整数计数器信号量sem的操作。一次的操作。一次P操作使操作使sem减一,而一次减一,而一次V操作使操作使sem加一。进程(或加一。进程(或线程)根据信号量的值来判断是否对公共资源具有访线程)根据信号量的值来判断是否对公共资源具有访问权限。当信号量问权限。当信号量sem的值大于等于零时,该进程(或的值大于等于零时,该进程(或线程)具有公共资源的访问权限;相反,当信号量线程)具有公共资源的访问权限;相反,当信号量sem的值小于零时,该进程(或线程)就将阻塞直到信号的值小于零时,该进程

101、(或线程)就将阻塞直到信号量量sem的值大于等于的值大于等于0为止。为止。多线程编程多线程编程v信号量线程控制信号量线程控制vPV原子操作主要用于进程或线程间的同步和互斥这两种原子操作主要用于进程或线程间的同步和互斥这两种典型情况。典型情况。多线程编程多线程编程v信号量线程控制信号量线程控制vLinux实现了实现了POSIX的无名信号量,主要用于线程间的互斥与同步。的无名信号量,主要用于线程间的互斥与同步。这里主要介绍几个常见函数。这里主要介绍几个常见函数。sem_init()用于创建一个信号量,并初始化它的值。用于创建一个信号量,并初始化它的值。sem_wait()和和sem_trywait

102、()都相当于都相当于P操作,在信号量大于零时它操作,在信号量大于零时它们都能将信号量的值减一,两者的区别在于若信号量小于零时,们都能将信号量的值减一,两者的区别在于若信号量小于零时,sem_wait()将会阻塞进程,而将会阻塞进程,而sem_trywait()则会立即返回。则会立即返回。sem_post()相当于相当于V操作,它将信号量的值加一同时发出信号来唤操作,它将信号量的值加一同时发出信号来唤醒等待的进程。醒等待的进程。sem_getvalue()用于得到信号量的值。用于得到信号量的值。sem_destroy()用于删除信号量。用于删除信号量。多线程编程多线程编程vsem_init()函

103、数语法函数语法多线程编程多线程编程vsem_wait()函数语法函数语法多线程编程多线程编程vpthread_create()函数的第二个参数(函数的第二个参数(pthread_attr_t *attr)表示线程的属性。如果该值设为)表示线程的属性。如果该值设为NULL,就是采用,就是采用默认属性,线程的多项属性都是可以更改的。这些属性主默认属性,线程的多项属性都是可以更改的。这些属性主要包括绑定属性、分离属性、堆栈地址、堆栈大小以及优要包括绑定属性、分离属性、堆栈地址、堆栈大小以及优先级。其中系统默认的属性为非绑定、非分离、缺省先级。其中系统默认的属性为非绑定、非分离、缺省1M的堆栈以及与父

104、进程同样级别的优先级。的堆栈以及与父进程同样级别的优先级。多线程编程多线程编程v绑定属性绑定属性绑定属性就是指一个用户线程固定地分配给一个内核绑定属性就是指一个用户线程固定地分配给一个内核线程,因为线程,因为CPU时间片的调度是面向内核线程(也就时间片的调度是面向内核线程(也就是轻量级进程)的,因此具有绑定属性的线程可以保是轻量级进程)的,因此具有绑定属性的线程可以保证在需要的时候总有一个内核线程与之对应。而与之证在需要的时候总有一个内核线程与之对应。而与之对应的非绑定属性就是指用户线程和内核线程的关系对应的非绑定属性就是指用户线程和内核线程的关系不是始终固定的,而是由系统来控制分配的。不是始

105、终固定的,而是由系统来控制分配的。 v分离属性分离属性 分离属性是用来决定一个线程以什么样的方式来终止分离属性是用来决定一个线程以什么样的方式来终止自己。自己。 多线程编程多线程编程vpthread_attr_init()函数对属性进行初始化函数对属性进行初始化vpthread_attr_init()函数语法函数语法多线程编程多线程编程vpthread_attr_setscope()函数设置线程绑定属性函数设置线程绑定属性vpthread_attr_setscope()函数语法函数语法多线程编程多线程编程vpthread_attr_setdetachstate()函数设置线程分离属性函数设置线

106、程分离属性vpthread_attr_setdetachstate()函数语法函数语法多线程编程多线程编程vpthread_attr_getschedparam()函数获得线程优先级函数获得线程优先级vpthread_attr_getschedparam()函数语法函数语法多线程编程多线程编程vpthread_attr_setschedparam()函数设置线程优先级函数设置线程优先级vpthread_attr_setschedparam()函数语法函数语法思考题思考题v1. C语言有何特点,为什么说它适合嵌入式系统开发?语言有何特点,为什么说它适合嵌入式系统开发?v2. 简述简述linux下

107、下C语言开发流程,分别要用什么工具软件。语言开发流程,分别要用什么工具软件。v3. VIM编辑器有几种模式,各模式下主要实现什么功能?编辑器有几种模式,各模式下主要实现什么功能?v4. 举例说明编译器编译过程可细分为几个阶段,每个阶段举例说明编译器编译过程可细分为几个阶段,每个阶段 产生什么类型的文件。产生什么类型的文件。v5. GDB调试器有何功能?什么是远程调试?调试器有何功能?什么是远程调试?v6. Make工程管理器有何作用?工程管理器有何作用?v7. Makefile文件中有哪些变量,分别有何作用?文件中有哪些变量,分别有何作用?v8. 简述在简述在Eclipse环境下开发环境下开发

108、C语言程序的流程?语言程序的流程?v9. 什么是什么是CVS,其基本工作思路是什么?,其基本工作思路是什么?思考题思考题v10. 基本基本I/O操作函数有哪些,分别实现什么功能。操作函数有哪些,分别实现什么功能。v11. 什么是程序、进程、线程,三者有何区别?什么是程序、进程、线程,三者有何区别?v12. 进程间通信有哪几种方式?进程间通信有哪几种方式?v13. 什么是守护进程?简述创建守护进程的步骤。什么是守护进程?简述创建守护进程的步骤。v14. 简述简述exit()和和_exit()的区别。的区别。v15. 为什么说无名管道只能用于具有亲缘关系的进程之间为什么说无名管道只能用于具有亲缘关系的进程之间的通信?的通信?嵌入式嵌入式嵌入式嵌入式LinuxLinux操作系统操作系统操作系统操作系统

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 医学/心理学 > 基础医学

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号