linux线程编程6,6.1 linux进程和线程编程.ppt

253b171540df25e1b84436cbe50dfc72.gif6.1 linux进程和线程编程.ppt

Linux进程和线程编程 Linux 进程环境,6.1 进程,进程可以看做是一个正在执行的程序,进程需要一定的资源,如cpu时间、内存、文件和I/O设备等,来完成其任务,这些资源是在创建进程或者进程执行时分配的。 进程在多数系统是工作单元,这样的系统由一组进程组成,操作系统进程执行系统代码,用户进程执行用户代码。通过(多个)CPU在进程之间的切换,从而使操作系统更为高效。 进程是执行中的程序,这是一种非正式的说法,进程不只是程序代码,程序代码有时称为文本段,进程还包括当前活动,通过程序计数器的值和处理器寄存器的内容来表示,另外进程常通过进程堆栈段(包含临时数据,如方法参数、返回地址、局部变量)和数据段。 进程是一个活动的实体,他有一个程序计数器用来表示下一个要执行的指令和相关资源的集合,6.1.1Linux 进程环境,如果要 编写一个高质量的程序必须要了解程序运行的内部机制,而了解一个程序的启动和退出是了解程序运行内部机制的基础,所以我们先了解shell中启动一个程序的方法和过程,及程序由外存加载到内存的过程,和程序在退出时所作的操作。,Linux shell启动程序,Shell本身可以运行两种文件,一种是二进制文件,另一种是解释器文件(shell脚本)。 程序路径 命令参数(例如hello) 程序运行时会在指定的路径下搜索文件,如果存在则shell会使用加载程序将这些文件加载到内存中。否则提示执行失败。 Linux shell中的命令也是一些可以执行的二进制文件,他们存放在PATH路径指定的文件夹下,用户可以自己定义自己的命令,放置在PATH指定的目录中,则可以像执行命令一样执行自己的程序。,Linux 加载一个程序,一个源程序代码,进过编译、链接之后加载到内存中执行,下面介绍3个概念程序格式、内部结构、程序头。 程序格式程序在经过编译后变成了二进制代码,但是并不是每个程序的内部结构都是一样的,同一类程序使用同样的内部结构,他们的内部结构采用相同的套路,这种类称之为格式。 内部结构一个C程序可能被编译成若干个段,这若干个段是linux下c的典型段,单并不是所有的段,有些格式的程序,可能段多,有些可能段少,此外段的顺序可能也不相同,程序段的数目和顺序成为程序的存储结构。 程序头一个程序需要一个独立的单元记录一些统计信息,这些信息包括二进制代码段的大小,段的次序,操作系统在加载程序时,需要程序头提供信息,分配供程序运行的内存等。,Linux 加载一个程序,加载地址,了解加载过程后,可以得出一个结论,就是加载器每次加载前需要分配地址空间,所以每次加载程序时不会使用相同的地址。,退出程序,对于退出程序的理解有助于在以后的编程中防止很多错误发生, 在linux环境中,退出有3种形式,进程自愿退出,进程收到一个信息号退出,以及进程执行一个导致异常的操作后退出。 自愿退出这种一般为return和exit语句,进程退出时系统要回收进程所分配的资源,例如进程的地址空间、文件描述符等,在回收资源的同时,操作系统要对每一项资源进行善后处理,例如对于打开的文件,在释放文件描述如的同时还要将缓冲区的内容“冲洗”到外存中保证文件缓冲区中的内容和外存一致。 一个进程的资源分为两部分,一部分资源在进程结束就会释放,另一部分则由系统保存,用于以后对进程进行统计,前者往往供进程本身使用,后者往往提供给进程的父进程,因此,用于统计的资源是否释放是由进程的父进程决定的,如果父进程不释放进程资源,则会出现僵尸进程,由此可见进程正常退出后,出了操作系统所作的资源释放外,父进程释放掉进程的统计资源也是相当重要的。,程序退出流程,退出程序,退出进程的第二种情况是收到一个信号后退出吗,这种情况往往出现在父进程对子进程的控制上,例如在shell中如果不想让其执行,可以按CtrlC强行终止一个程序执行,这一操作实际上是是由shell(父进程),向运行的程序发出了一个终止信号,子进程在收到信号后,也会想自愿退出一样处理分配资源,正常退出。 第3中情况,是在预料之外退出的,程序没有准备好,这时候操作系统也会对其资源进行回收,但是有可能不会对这些资源做善后处理,这样的退出方式称为异常退出。,进程终止处理函数,Linux环境下允许在进程推出的时候调用一些用户自定义函数,这些函数称为终止函数。 Linux规定最多可以设置32个这样的进程终止函数。Linux使用atexit函数设置进程终止处理函数,其原型如下 include Int atexitvoid *funcvoid; Atexit函数的参数是一个函数指针。该函数指针指向一个返回值和参数都是void型的函数,也就是说,进程终止函数不接受任何参数,因为他是在进程结束时调用的,因此也不返回任何值。如果成功的设置了进程终止处理函数,atexit函数返回0,失败则返回非零值。因此在检查atexit的返回值时,不应检查atexit的返回值是否为-1.进程终止函数处理的调用顺序与设置时相反。 perror s 用 来 将 上 一 个 函 数 发 生 错 误 的 原 因 输 出 到 标 准 错误 stderr 。参数 s 所指的字符串会先打印出,后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。,进程终止处理函数,第三次设置的进程终止处理函数f2,第二次设置的进程终止处理函数f1,第一次设置的进程终止处理函数f1栈顶,先执行,栈底,先执行,Linux 进程内存管理-数据内部存储,内存是计算机的敏感资源,熟练掌握对内存的操作是一个程序员的必备素质。 数据的内部存储方式大小端法 在c中,不同的数据类型占用的空间是不同的,例如char类型占用1个字节,而int占用4个字节,数据内部存储,存储其中的大小端法存储是是由处理器决定的和linux系统无关,下面的代码展示了如何判断读者使用的机器是使用那种存储方式。该程序首先定义了一个整形变量a,使用一个指针保存该变量存储空间的首地址,通过打印起始地址后不同长度的内存中的数据,可以判断当前运行的体系结构是大端法还是小端法。 这个程序可以用来测试目标机器(开发板)的存储方式。,Linux C程序存储布局,一个C语言的程序所占用的内存分为一下几个部分, 栈(stack)由编译器自动分配释放,采访程序的参、局部变量、返回地址等,其操作方式类似与数据结构中的栈。 堆(heap)一般由程序员动态分配(调用malloc函数)和释放(调用free函数),若程序员不释放,在程序结束时可能由操作系统收回。 数据段(data)存放全局变量、静态变量、常数。根据存放的数据又可以方位普通数据段(包括可写/只读数据段,存放静态初始化的全局变量和常量)、bbs数据段(存放未初始化的全局变量) 代码段(code)用于存放程序代码是进程中最重要的一段,该段是由CPU执行的指令部分,通常又称为代码段。,Linux C程序存储布局,Linux C程序存储布局-数据段,初始化数据段(data),它包含程序中明确给定初始值的全局变量和静态变量。例如int max100全局变量或者static int count10;初始化数据段在编译时确定该段的大小,在程序运行过程中,该段的大小是不能发生变化。 非初始化数据段(bbs)存储在这个段中的数据通常是没有明确给定初始值的全局变量,和静态变量,如int max;static int count; 一般情况下bbs段中的内容不会作为程序文件中的一部分,而被保持到外存中,系统只记录这些未被初始化变量的一些大小、属性等信息的开销。,Linux C程序存储布局-栈,所有的自动变量(局部变量局部变量,如不作专门说明为静态变量,都是动态分配存储空间,存储在动态存储区中 )以及函数调用时需要保存的信息(返回地址、函数调用前各个寄存器的值)等都要存储在栈上。每次调用函数时栈会随着函数的调用而生长,随着函数调用高的结束而消亡。 由于绝大多数自动变量存储在栈中,所以自动变量的作用域往往只在函数内,其生命周期也往往只持续到函数调用结束。 在C语言中给一个典型的错误就是将一个指向局部变量的指针作为函数的返回值返回。,Linux C程序存储布局-栈,这个实例演示了这种错误,该程序定义了一个字符串合并函数,改函数将要合并的两个字符串作为参数传入,在一个局部数组中合并后返回改局部数组的首地址,由于该数组是一个局部变量,因此在函数返回时其数组空间已经作废了。,Linux C程序存储布局-堆,堆用于用户申请的空间,系统通常在堆中进行内存动态分配例如 Int *p (int *)malloc(sizeof(int; 指针p所指的内存块就分配在堆中,堆位于数据段和栈之间, 栈和堆的区别栈是自动分配的,堆需要自己申请 堆是向高地址扩展的数据结构,是不连续的内存空空间,栈是向低地址扩展的数据结构,是连续的空间。 堆是malloc语句分配的内存,速度慢易产生碎片,但是使用方便,栈是系统自动分配的速度快,但程序员一般无法控制。,谢谢,

你可能感兴趣的:(linux线程编程6)