Linux 环境下的C语言编程ppt课件.ppt
Linux 环境下的 C语言编程,第一部分: Linux下的C编程实战之开发平台搭建,准备工作,建议在PC内存足够大的情况下,不要直接安装Linux操作系统,最好把它安装在运行VMWare虚拟机软件的Windows平台上,如下图:,1. Vim和Emacs编辑器,在Linux平台下,可用任意一个文本编辑工具编辑源代码。Vim(vi improve)是Linux下功能强大的编辑器,是由UNIX系统下的传统文本编辑器vi发展而来,是vi的一个增强版本,有彩色和高亮等特性,对编程有很大帮助。主菜单-编程-vi Improved命令来运行x-windows下的vim。Emacs即Editor MACroS(编辑器宏)的缩写,是一种强大的文本编辑器,在程序员和其他以技术工作为主的计算机用户中广受欢迎。,使用vim编辑helloworld程序,使用emacs编辑helloworld程序,2.GCC编译器,GCC是Linux平台下最重要的开发工具,它是GNU的C和C+编译器,其基本用法为:gcc options filenames 该命令按编译选项(参数options)指定的操作对给定的文件进行编译处理。编译一输出“Hello World”的程序: main() printf(Hello Worldn);,2.GCC编译器,最简单的编译方法是不指定任何编译选项,它会为目标程序生成默认的文件名 a.outgcc helloworld.co选项:编译来为将产生的可执行文件指定一个文件名。例如,将上述名为helloworld.c的C程序编译为名叫helloworld的可执行文件,输入如下命令:gcc -o helloworld helloworld.c,2.GCC编译器-常用选项,c选项:告诉GCC仅把源代码(.c文件)编译为目标代码(.o文件)而跳过汇编和连接的步骤;它能使编译多个C程序时的速度更快且容易管理。例如用户将已编辑好的test.c文件编译成名为test.o的目标文件。可以使用命令 gcc -c test.cs选项:告诉GCC 在为 C代码产生了汇编语言文件后停止编译。GCC 产生的汇编语言文件的缺省扩展名是.s。将生成helloworld.c的汇编代码,使用的是AT&T汇编。用emacs打开汇编代码如下图。,用emacs打开的Hello.c的汇编代码,2.GCC编译器-常用选项,E选项:指示编译器仅对输入文件进行预处理,但不汇编和连接O(-O1)选项:告诉GCC对源代码进行基本优化从而使得程序执行地更快;而-O2选项告诉GCC产生尽可能小和尽可能快的代码。使用-O2选项编译的速度比使用-O时慢,但产生的代码执行速度会更快。Wall 选项:显示附加的警告信息。例如在上述程序中去掉 return 0;语句,之后重新编译 gcc Wall o hello hello.c将得到的警告信息:hello.c : 5:warning:control reaches end of non-void function,3. GDB 调试器,GCC用于编译程序,而Linux的另一个GNU工具gdb则用于调试程序。gdb是一个用来调试C和C+程序的强力调试器,通过它进行一系列调试工作。gdb主要提供一下功能:监视程序中变量的值得变化设置断点,使程序在指定的代码上暂停执行,便于观察单步执行代码分析崩溃程序产生的core文件,3. GDB 调试器,gdb最常用的命令如下file:装入想要调试的可执行文件。kill:终止正在调试的程序。 list:列表显示源代码。 next:执行一行源代码但不进入函数内部。 step:执行一行源代码而且进入函数内部。 run:执行当前被调试的程序 quit:终止gdbwatch:监视一个变量的值 break:在代码里设置断点,程序执行到这里时挂起,3. GDB 调试器,举例说明怎样用GDB调试一个求0+1+2+3+99的程序:/* Filename:sum.c */main() int i, sum; sum = 0; for (i = 0; i 100; i+) sum + = i; printf(the sum of 1+2+.+ is %d, sum);,3. GDB 调试器,3. GDB 调试器,执行如下命令编译sum.c(加-g选项产生debug信息): gcc g o sum sum.c在命令行上键入gdb sum并按回车键就可以开始调试sum了,再运行run命令执行sum,屏幕上将看到如下内容:,3. GDB 调试器,list命令:list命令用于列出源代码,对上述程序运行list,将出现如下画面(源代码被标行号):,3. GDB 调试器,根据列出的源程序,如果将断点设置在第4行,只需在gdb 命令行提示符下键入如下命令设置断点:(gdb)break 4Breakpoint 1 at 0 x8048338:file sum.c line 4这时再run,程序会停止在第4行:Starting program:/root/sumBreakpoint 1,main() at sum.c line 44 sum=0,3. GDB 调试器,设置断点的另一种语法是 break ,它在进入指定函数(function)时停住。相反的,clear用于清除所有的已定义的断点clear 清除设置在函数上的断点;clear 则清除设置在指定行上的断点。,3. GDB 调试器,watch命令:用于观查变量或表达式的值watch命令观查sum变量只需要运行:watch sumwatch命令观查表达式:watch 为表达式(变量)expr设置一个观察点,变量表达式值有变化时,程序会停止执行。要观查当前设置的watch,可以使用info watchpoints命令。,3. GDB 调试器,next、step命令:next、step用于单步执行,在执行的过程中,被watch变量的变化情况将实时呈现(分别显示Old value和New value),如下图:next、step命令的区别在于step遇到函数调用,会跳转到该函数定义的开始行去执行,而next则不进入到函数内部,它把函数调用语句当作一条普通语句执行。,4.Make,编译和连接的区别编译器使用源码文件来产生某种形式的目标文件,在编译过程中,外部的符号参考并没有被解释或替换(即外部全局变量和函数并没有被找到)。因此,在编译阶段所报的错误一般都是语法错误。连接器则用于连接目标文件和程序包,生成一个可执行程序。在连接阶段,一个目标文件中对别的文件中的符号的参考被解释,如果有符号不能找到,会报告连接错误。,4.Make,编译和连接的一般步骤是:第一阶段把源文件一个一个的编译成目标文件,第二阶段把所有的目标文件加上需要的程序包连接成一个可执行文件。这样的过程需要使用大量的gcc命令。而make则使从大量源文件的编译和连接工作中解放出来,综合为一步完成。,4.Make,GNU Make的主要工作是读进一个文本文件,称为makefile。makefile文件记录了哪些文件(目的文件,目的文件不一定是最后的可执行程序,它可以是任何一种文件)由哪些文件(依靠文件)产生,用什么命令来产生。Make依靠此makefile中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话,make就执行相应的命令,以便更新目的文件。,4.Make,makefile文件的编写makefile文件是一个文本文件,用于描述整个项目和各个文件之间的依赖关系。它由多个规则组成。makefile文件的规则遵循以下结构#remark 注释行target:file1 file2 二进制文件或者目标文件command1 命令command2,4.Make,例如: 下面三个文件,add.h用于声明add函数,add.c提供两个整数相加的函数体,而main.c中调用add函数: /* filename:add.h */extern int add(int i, int j);/* filename:add.c */int add(int i, int j) return i + j;,/* filename:main.c */#include add.hmain() int a, b; a = 2; b = 3; printf(the sum of a+b is %d, add(a + b);,怎样为上述三个文件产生makefile呢?,4.Make,为上述三个文件产生makefile的方法如下: test : main.o add.o gcc main.o add.o -o test main.o : main.c add.h gcc -c main.c -o main.o add.o : add.c add.h gcc -c add.c -o add.o,4.Make,上述makefile文件的含义利用add.c和add.h文件执行gcc -c add.c -o add.o命令产生add.o目标代码。利用main.c和add.h文件执行gcc -c main.c -o main.o命令产生main.o目标代码。最后利用main.o和add.o文件(两个模块的目标代码)执行gcc main.o add.o -o test命令产生可执行文件test。可以使用gcc -MM main.c自动寻找源文件中的头文件,并形成依赖关系。输出为:main.o main.c add.h,4.Make,可在makefile中加入变量。另外,环境变量在make过程中也被解释成make的变量。这些变量是大小写敏感的,一般使用大写字母。要定义一个变量,只需要在一行的开始写下这个变量的名字,后面跟一个=号,再跟变量的值。引用变量的方法是写一个$符号,后面跟(变量名)。,4.Make,把前面的 makefile 利用变量重写一遍(并假设使用-Wall -O g编译选项):OBJS = main.o add.oCC = gccCFLAGS = -Wall -O -gtest : $(OBJS)$(CC) $(OBJS) -o testmain.o : main.c add.h$(CC) $(CFLAGS) -c main.c -o main.oadd.o : add.c add.h$(CC) $(CFLAGS) -c add.c -o add.o,4.Make,makefile 中还可定义清除(clean)目标,可用来清除编译过程中产生的中间文件,例如在上述makefile文件中添加下列代码: clean: rm -f *.o运行make clean时,将执行rm -f *.o命令,删除所有编译过程中产生的中间文件。,4.Make,Make的运行GUN make默认在当前的目录下一次查找GUNmake文件,Makefile文件和makefile文件,找到后读取文件执行。给make命令指定一个特殊名字的makefile文件make f hchen.mk,4.Make,自己动手编写makefile仍然是很复杂和烦琐的,而且很容易出错。因此,GNU也提供了Automake和Autoconf来辅助快速自动产生makefile。,4.Make,使用autoconf和automake来进行自动化配置和生成Makefile的流程可以概括如下:运行autoscan命令。将configure.scan文件重命名为configure.in,并修改configure.in文件。运行aclocal命令得到aclocal.m4文件。运行autoconf命令得到configure文件。在工程目录下新建Makefile.am文件,如果存在子目录,子目录中也要创建此文件。将/usr/share/automake-1.X/目录下的depcomp和compile文件复制到需要处理目录下。运行automake -a命令得到Makefile.in文件。运行./configure脚本,4.Make,从例子程序helloworld开始。过程如下:新建三个文件: helloworld.cconfigure.inMakefile.am然后执行 aclocal; autoconf; automake -add-missing; ./configure; make; ./helloworld Makefile被产生出来,而且可以将helloworld.c编译通过。,小结,本部分主要阐述了Linux程序的编写、编译、调试方法及make,实际上是引导学习怎样在Linux下编程,为后续章节做好准备。,第二部分 Linux下的C编程实战之文件系统编程,Linux平台下文件编程,在Linux平台下对文件编程可以使用两类函数:Linux操作系统文件API;C语言I/O库函数。 前者依赖于Linux系统调用,后者实际上与操作系统是独立的,因为在任何操作系统下,使用C语言I/O库函数操作文件的方法都是相同的。,1. Linux文件API-创建,创建int create(const char *filename, mode_t mode); 参数mode指定新建文件的存取权限,它同umask一起决定文件的最终权限(mode 该调用将umask设置为newmask,然后返回旧的umask,它只影响读、写和执行权限。,1. Linux文件API-创建,mode可以是以下情况的组合,可以通过上述宏进行“或”逻辑产生标志。,1. Linux文件API-创建,mode可以是以下情况的组合,可以通过上述宏进行“或”逻辑产生标志。,1. Linux文件API-创建,用数字来表示:Linux总共用5个数字来表示文件的各种权限:第一位表示设置用户ID;第二位表示设置组ID;第三位表示用户自己的权限位;第四位表示组的权限;最后一位表示其他人的权限。每个数字可以取1(执行权限)、2(写权限)、4(读权限)、0(无)或者是这些值的和。,1. Linux文件API-创建,用数字来表示:例如,要创建一个用户可读、可写、可执行,但是组没有权限,其他人可以读、可以执行的文件,并设置用户ID位。应该使用的模式是1(设置用户ID)、0(不设置组ID)、7(1+2+4,读、写、执行)、0(没有权限)、5(1+4,读、执行)即10705,1. Linux文件API-打开,打开int open(const char *pathname, int flags);int open(const char *pathname, int flags, mode_t mode); 如果文件打开成功,open函数会返回一个文件描述符,以后对该文件的所有操作就可以通过对这个文件描述符进行操作来实现。open函数有两个形式,其中pathname是要打开的文件名(包含路径名称,缺省是认为在当前路径下面) 。,1. Linux文件API-打开,打开flags可以是下面的一个值或者是几个值的组合,O_RDONLY、O_WRONLY、O_RDWR三个标志只能使用任意的一个。,1. Linux文件API-打开,打开如果使用了O_CREATE标志,则使用的函数是int open(const char *pathname,int flags,mode_t mode); 这时要指定mode标志,用来表示文件的访问权限。以O_CREAT为标志的open实际上实现了文件创建的功能。例如: open(test, O_CREAT, 10705); open(test, O_CREAT, S_IRWXU | S_IROTH | S_IXOTH | S_ISUID );,1. Linux文件API-读写,读写Linux中提供文件读写的系统调用是read、write函数: int read(int fd, const void *buf, size_t length); int write(int fd, const void *buf, size_t length);参数buf为指向缓冲区的指针,length为缓冲区的大小(以字节为单位)。,1. Linux文件API-读写,int read(int fd, const void *buf, size_t length);函数read实现从文件描述符fd所指定的文件中读取length个字节到buf所指向的缓冲区中,返回值为实际读取的字节数。int write(int fd, const void *buf, size_t length);函数write实现将把length个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数。,1. Linux文件API-定位,定位:对于随机文件,我们可以随机的指定位置读写,使用如下函数进行定位: int lseek(int fd, offset_t offset, int whence);lseek()将文件读写指针相对whence移动offset个字节。操作成功时,返回文件指针相对于文件头的位置。参数whence可使用下述值:SEEK_SET:相对文件开头SEEK_CUR:相对文件读写指针的当前位置SEEK_END:相对文件末尾,1. Linux文件API-定位,定位:offset可取负值,例如下述调用可将文件指针相对当前位置向前移动5个字节: lseek(fd, -5, SEEK_CUR);由于lseek函数的返回值为文件指针相对于文件头的位置,因此下列调用的返回值就是文件的长度: lseek(fd, 0, SEEK_END);,1. Linux文件API-关闭,关闭当操作完成以后,要关闭文件,只要调用close即可,其中fd是要关闭的文件描述符: int close(int fd);,1. Linux文件API-编程实例,例程:编写一个程序,在当前目录下创建用户可读写文件“hello.txt”,在其中写入“Hello, software weekly”,关闭该文件。再次打开该文件,读取其中的内容并输出在屏幕上。,#include /类型#include /获取文件属性#include /文件描述词操作#include #define LENGTH 100main()int fd, len;char strLENGTH; fd = open(“hello.txt”, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); /* 创建并打开文件 ,以读写的方式打开,用户可以读、用户可以写*/,1. Linux文件API-编程实例,if (fd) write(fd, Hello, Software Weekly, strlen(Hello, software weekly); /* 写入Hello, software weekly字符串 */close(fd);fd = open(“hello.txt”, O_RDWR); /以读写方式打开 len = read(fd, str, LENGTH); /* 读取文件内容 */strlen = 0;printf(%sn, str);close(fd);,1. Linux文件API-编程实例,1. Linux文件API-编程实例,编译并运行,执行结果如下rootdl root#gcc g o hello ./hello.crootdl root# ./helloHello,software weekly,3.C语言库函数,C库函数的文件操作实际上是独立于具体的操作系统平台的,不管是在DOS、Windows、Linux还是在VxWorks中都是这些函数.,3.C语言库函数-创建和打开,创建和打开FILE *fopen(const char *path, const char *mode);fopen()实现打开指定文件,参数path字符串包含欲打开的文件路径及文件名 ,mode为打开模式.返回值:文件指针名。必须被说明为FILE类型的指针变量 。,3.C语言库函数-创建和打开,C语言中支持的打开模式如下表,其中b用于区分二进制文件和文本文件,在DOS、Windows系统中是有区分的,但Linux不区分二进制文件和文本文件。,3.C语言库函数-读写,读写:C库函数支持以字符、字符串等为单位,支持按照某中格式进行文件的读写,这一组函数为:int fgetc(FILE *stream); 从流中读一个字符int fputc(int c, FILE *stream);送一个字符到流中char *fgets(char *s, int n, FILE *stream);从流中读取一字符串 int fputs(const char *s, FILE *stream);送一个字符串到流中,3.C语言库函数-读写,int fprintf(FILE *stream, const char *format, .);传送格式化输出到一个文件中,成功时返回转换的字节数,失败时返回一个负数。 fprintf( stream, %s%c, s, c ); fprintf( stream, %dn, i ); int fscanf (FILE *stream, const char *format, .);从一个流中执行格式化输入 if (fscanf(stdin, %d, ,3.C语言库函数-读写,读写:size_t fread(void *ptr, size_t size, size_t n, FILE *stream);size_t fwrite (const void *ptr, size_t size, size_t n, FILE *stream);fread()实现从流stream中读取n个字段,每个字段为size字节,并将读取的字段放入ptr所指的字符数组中,返回实际已读取的字段数。write()实现从缓冲区ptr所指的数组中把n个字段写到流stream中,每个字段长为size个字节,返回实际写入的字段数。,3.C语言库函数-定位,定位 :C库函数还提供了读写过程中的定位能力,这些函数包括:int fgetpos(FILE *stream, fpos_t *pos); /将文件流的文件位置指示符存储在pos变量中int fsetpos(FILE *stream, const fpos_t *pos);/将文件指针定位在pos指定的位置上 返回值:成功返回0,否则返回非0。,#include void main( void ) FILE *fp; fpos_t pos; char buffer50; if( (fp = fopen( test.txt, rb ) = NULL ) /*以只读方式打开名为test.txt的文件*/ printf( Trouble opening filen ); else pos = 10; /*设置pos值*/ if( fsetpos( fp, ,else /*从新定位的文件指针开始读取16个字符到buffer缓冲区*/fread( buffer, sizeof( char ), 16, fp );printf( 16 bytes at byte %ld: %.16sn, pos, buffer ); /*显示结果*/ fclose( fp );,3.C语言库函数-定位,首先,程序以只读方式打开名为test.txt的文件。在这里,test.txt文件中已存入字符串This is a test for testing the function of fsetpos.将pos设置为10。应用fsetpos函数将文件指针fp按照pos指定的位置在文件中定位。这样文件指针fp指向字符串中test的字母t。再从新定位的文件指针开始读取16个字符到buffer缓冲区,也就是说读取字符串test for testing到缓冲区buffer。最后显示结果:16 bytes at byte 10: test for testing,3.C语言库函数-定位,int fseek(FILE *stream, long offset, int whence);stream为文件指针offset为偏移量,整数表示正向偏移,负数为负向偏移whence设定从文件的哪里开始偏移,可能取值为:SEEK_SET: 文件开头 0SEEK_CUR: 当前位置 1SEEK_END: 文件结尾 2fseek(fp,100L,0);把fp指针移动到离文件开头100字节处;fseek(fp,100L,1);把fp指针移动到离文件当前位置100字节处;fseek(fp,100L,2);把fp指针退回到离文件结尾100字节处。,3.C语言库函数-关闭,关闭:利用C库函数关闭文件的操作: int fclose (FILE *stream);,3.C语言库函数-编程实例,例程:编写一个程序,在当前目录下创建用户可读写文件“hello.txt”,在其中写入“Hello, software weekly”,关闭该文件。再次打开该文件,读取其中的内容并输出在屏幕上。,#include #define LENGTH 100main()FILE *fd;char strLENGTH;fd = fopen(hello.txt, w+); /* 创建并打开文件 */if (fd)fputs(Hello, Software Weekly, fd); /* 写入Hello, software weekly字符串 */fclose(fd);fd = fopen(hello.txt, r);fgets(str, LENGTH, fd); /* 读取文件内容 */printf(%sn, str);fclose(fd);,3.小结,Linux提供的虚拟文件系统为多种文件系统提供了统一的接口,Linux的文件编程有两种途径:基于Linux系统调用;基于C库函数这两种编程所涉及到文件操作有新建、打开、读写和关闭,对随机文件还可以定位。,第二部分 Linux下的C编程实战之进程控制与进程通信编程,1.进程的基本概念,进程是具有一定功能的程序,是关于一个数据集合的一次执行过程。多个进程可以同时运行。Linux进程在内存中包含三部分数据:代码段:存放了程序的代码,代码段可以为机器中运行同一程序的数个进程共享。堆栈段:存放的是子程序(函数)的返回地址、子程序的参数及程序的局部变量。数据段:存放程序的全局变量、常数以及动态数据分配的数据空间。堆栈段和数据段不能为运行同一程序的数个进程共享。,2.进程控制-进程的创建,(1)派生进程系统调用fork用于派生一个进程,其说明如下: #include pid_t fork(void); pid_t vfork(void);调用fork时,系统创建一个与当前进程(父进程)相同的新进程(子进程)。子进程是父进程的一个复制,子进程拷贝父进程的数据段、代码段,2.进程控制-进程的创建,fork调用将执行两次返回,它将从父进程和子进程中分别返回。从父进程返回时的返回值为子进程的PID,而从子进程返回时的返回值为0,并且返回都将执行fork之后的语句。调用出错时,返回值为-1,#include#include#includeint main( ) pid_t pid; pid=fork(); if(pid)0) printf(“fork error!n”); exit(1); else if(pid=0) printf(“child process is printing.IDis %dn”,getpid(); else printf(“parent process is printing. ID is %dn”,getpid(); ,拷贝代码段的实例,运行结果:rootlwm liweimeng# gcc fork1.c -o fork1rootlwm liweimeng# ./fork1I am the child process,ID is 4238I am the parent process,ID is 4237因为 fork()函数用于从已存在的进程中创建一个新的子进程,在 pid=fork();语句之前只有父进程在运行,而在之后,父进程和新创建的子进程都在运行,子进程拷贝父进程的代码段,所以子进程中同样有 if(pid0) printf(error in fork!);else if(pid=0) printf(I am the child process,ID is %dn,getpid();else printf(I am the parent process,ID is %dn,getpid();,2.进程控制-进程的创建,#include#includeint main( ) pid_t pid; Int count =0; pid=fork(); Count+; Printf(“count=%dn”,count); Return 0;输出:Count=1 Count=1,拷贝数据段的实例,将被父子进程各执行一次,但是子进程执行时使自己的数据段里面的(这个数据段是从父进程那 copy过来的一模一样)count+1,同样父进程执行时使自己的数据段里面count+1,互不影响,2.进程控制-进程的创建,vfork的作用和fork基本相同,区别在于:vfork并不完全复制父进程的数据段,而是和父进程共享数据段。调用vfork对于父子进程的执行次序有所限制。调用vfork函数将使父进程挂起,直至子进程返回。vfork 保证子进程先运行,在她调用 exec 或 exit 之后父进程才可能被调度运行。,#include #include #include int main(void)pid_t pid;int count=0;pid=vfork();if(pid=0) count+; _exit(0); else count+; printf(count= %dn,count); return 0;,2.进程控制-进程的创建,在子进程调用 exec 或 exit 之前与父进程数据是共享的,所以子进程退出后把父进程的数据段 count 改成 1 了,子进程退出后,父进程又执行,最终就将count 变成了 2运行结果: rootlwm liweimeng# gcc fork2.c -o fork2 rootlwm liweimeng# ./fork2 count= 2,2.进程控制-进程的创建,(2)创建执行其他程序的进程 使用exec族的函数执行新的程序,以新的子进程完全替代原有的进程。int execl(const char *pathname,const char *arg,);int execlp(const char *filename,conxt char *arg,);int execle(const char *pathname,conxt char *arg,char #const encp);int execv(const char *pathname, char *const argv);int execvp(const char *filename, char *const argv);int execve(const char *pathname, char *const argv,char *const envp);,2.进程控制-进程的创建,exec函数族的特点用于启动一个指定路径和文件名的进程。某进程一旦调用了exec类函数,正在执行的程序结束,系统把代码段换成新的程序的代码,原有的数据段和堆栈段也被放弃,新的数据段和堆栈段被分配,但是进程号被保留。结果为:系统认为正在执行的还是原来的进程,但是进程对应的程序被替换了。,2.进程控制-进程的创建,fork和exec搭配实现让父进程的代码执行又启动一个新的指定的进程。,execl()使用范例#include #include #include main() pid_t pid; printf(Now only one processn); printf(Calling fork.n); pid=fork(); if(pid=0) /*进程为子进程*/ printf(I am the childn);execl(/bin/ls,-l,NULL);/*如果execl返回,说明调用失败*/perror(execl failed to run ls); exit(1); ,2.进程控制-进程的创建,else if(pid0) /*进程为父进程*/ printf(Im the parent, my childs pid is %dn,pid); execl(/bin/ps,-c,NULL); /*如果execl返回,说明调用失败*/ perror(execl failed to run ls); exit(1); else printf(Fork fall!n);,2.进程控制-进程的创建,Clone此函数是fork的变形,对父子进程的共享资源提供了更多的控制。可以使得创建的子进程共享父进程的资源。函数原型:int clone(int(*fn)(void),void *child_stack,int flags,void *arg)fn是函数指针,指向要执行的函数child_stack子进程堆栈段的指针flags用于不同继承内容的标识,2.进程控制-进程的创建,Flags标识的选取,2.进程控制-进程的创建,int variable, fd; int do_something() variable = 42;close(fd);_exit(0);,2.进程控制-进程的创建,int main(int argc, char *argv) void *child_stack;char tempch;variable = 9;fd = open(test.file, O_RDONLY);child_stack = (void *) malloc(16384);printf(The variable was %dn, variable);clone(do_something, child_stack, CLONE_VM|CLONE_FILES, NULL);sleep(1); /* 延时以便子进程完成关闭文件操作、修改变量*/,2.进程控制-进程的创建,printf(The variable is now %dn, variable);if (read(fd, ,2.进程控制-进程的创建,运行输出:The variable is now 42File Read Error程序的输出结果说明,子进程将文件关闭并将变量修改(调用clone时用到的CLONE_VM、CLONE_FILES标志将使得变量和文件描述符表被共享),父进程随即就感觉到了,这就是clone的特点。,2.进程控制-进程的挂起,Sleep函数调用sleep可以用来使进程挂起指定的秒数。如果指定的挂起的时间到了,该调用的返回值为0;如果该函数调用被信号打断,则返回剩余挂起的时间数(指定的时间减去已经挂起的时间)函数原型 unsigned int sleep(unsigned int seconds),2.进程控制-进程的等待,WaitWait的作用是为发出调用的进程只要有子进程,就睡眠到他们中的一个终止为止。函数原型 pid_t wait(int *status);/子进程的结束状态值会由参数 status 返回 pid_t waitpid(pid_t pid, int *status, int options);/子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一块返回。 调用成功时,返回被置于等待状态的进程的pid,调用失败时,返回值为-1,2.进程控制-进程的等待,在子进程终止的情况下,wait调用将允许系统释放