版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux环境下的
C语言编程第一部分:Linux下的C编程实战之开发平台搭建准备工作建议在PC内存足够大的情况下,不要直接安装Linux操作系统,最好把它安装在运行VMWare虚拟机软件的Windows平台上,如下图:1.Vim和Emacs编辑器在Linux平台下,可用任意一个文本编辑工具编辑源代码。Vim(viimprove)是Linux下功能强大的编辑器,是由UNIX系统下的传统文本编辑器vi发展而来,是vi的一个增强版本,有彩色和高亮等特性,对编程有很大帮助。主菜单-编程-viImproved命令来运行x-windows下的vim。Emacs即EditorMACroS(编辑器宏)的缩写,是一种强大的文本编辑器,在程序员和其他以技术工作为主的计算机用户中广受欢迎。使用vim编辑helloworld程序使用emacs编辑helloworld程序2.GCC编译器GCC是Linux平台下最重要的开发工具,它是GNU的C和C++编译器,其基本用法为:gcc[options][filenames]
该命令按编译选项(参数options)指定的操作对给定的文件进行编译处理。编译一输出“HelloWorld”的程序:
main()
{
printf("HelloWorld\n");
}2.GCC编译器最简单的编译方法是不指定任何编译选项,它会为目标程序生成默认的文件名a.outgcc
helloworld.co选项:编译来为将产生的可执行文件指定一个文件名。例如,将上述名为helloworld.c的C程序编译为名叫helloworld的可执行文件,输入如下命令:gcc-ohelloworld
helloworld.c
2.GCC编译器-常用选项c选项:告诉GCC仅把源代码(.c文件)编译为目标代码(.o文件)而跳过汇编和连接的步骤;它能使编译多个C程序时的速度更快且容易管理。例如用户将已编辑好的test.c文件编译成名为test.o的目标文件。可以使用命令gcc-ctest.cs选项:告诉GCC在为C代码产生了汇编语言文件后停止编译。GCC产生的汇编语言文件的缺省扩展名是.s。将生成helloworld.c的汇编代码,使用的是AT&T汇编。用emacs打开汇编代码如下图。用emacs打开的Hello.c的汇编代码2.GCC编译器-常用选项E选项:指示编译器仅对输入文件进行预处理,但不汇编和连接O(-O1)选项:告诉GCC对源代码进行基本优化从而使得程序执行地更快;而-O2选项告诉GCC产生尽可能小和尽可能快的代码。使用-O2选项编译的速度比使用-O时慢,但产生的代码执行速度会更快。Wall选项:显示附加的警告信息。例如在上述程序中去掉return0;语句,之后重新编译gcc–Wall–ohellohello.c将得到的警告信息:hello.c:5:warning:controlreachesendofnon-voidfunction3.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()
{
inti,sum;
sum=0;
for(i=0;i<100;i++)
{
sum+=i;
}
printf("thesumof1+2+...+is%d",sum);
}3.GDB调试器3.GDB调试器执行如下命令编译sum.c(加-g选项产生debug信息):
gcc–g–osumsum.c在命令行上键入gdbsum并按回车键就可以开始调试sum了,再运行run命令执行sum,屏幕上将看到如下内容:3.GDB调试器list命令:list命令用于列出源代码,对上述程序运行list,将出现如下画面(源代码被标行号):
3.GDB调试器根据列出的源程序,如果将断点设置在第4行,只需在gdb
命令行提示符下键入如下命令设置断点:(gdb)break4Breakpoint1at0x8048338:filesum.cline4这时再run,程序会停止在第4行:Startingprogram:/root/sumBreakpoint1,main()atsum.cline44sum=03.GDB调试器设置断点的另一种语法是break<function>,它在进入指定函数(function)时停住。相反的,clear用于清除所有的已定义的断点clear<function>清除设置在函数上的断点;clear<linenum>则清除设置在指定行上的断点。3.GDB调试器watch命令:用于观查变量或表达式的值watch命令观查sum变量只需要运行:watchsumwatch命令观查表达式:watch<expr>
为表达式(变量)expr设置一个观察点,变量表达式值有变化时,程序会停止执行。要观查当前设置的watch,可以使用infowatchpoints命令。3.GDB调试器next、step命令:next、step用于单步执行,在执行的过程中,被watch变量的变化情况将实时呈现(分别显示Oldvalue和Newvalue),如下图:next、step命令的区别在于step遇到函数调用,会跳转到该函数定义的开始行去执行,而next则不进入到函数内部,它把函数调用语句当作一条普通语句执行。4.Make编译和连接的区别编译器使用源码文件来产生某种形式的目标文件,在编译过程中,外部的符号参考并没有被解释或替换(即外部全局变量和函数并没有被找到)。因此,在编译阶段所报的错误一般都是语法错误。连接器则用于连接目标文件和程序包,生成一个可执行程序。在连接阶段,一个目标文件中对别的文件中的符号的参考被解释,如果有符号不能找到,会报告连接错误。4.Make编译和连接的一般步骤是:第一阶段把源文件一个一个的编译成目标文件,第二阶段把所有的目标文件加上需要的程序包连接成一个可执行文件。这样的过程需要使用大量的gcc命令。而make则使从大量源文件的编译和连接工作中解放出来,综合为一步完成。4.MakeGNUMake的主要工作是读进一个文本文件,称为makefile。makefile文件记录了哪些文件(目的文件,目的文件不一定是最后的可执行程序,它可以是任何一种文件)由哪些文件(依靠文件)产生,用什么命令来产生。Make依靠此makefile中的信息检查磁盘上的文件,如果目的文件的创建或修改时间比它的一个依靠文件旧的话,make就执行相应的命令,以便更新目的文件。
4.Makemakefile文件的编写makefile文件是一个文本文件,用于描述整个项目和各个文件之间的依赖关系。它由多个规则组成。makefile文件的规则遵循以下结构#remark注释行target:file1file2[…]二进制文件或者目标文件command1命令command2[…]4.Make例如:下面三个文件,add.h用于声明add函数,add.c提供两个整数相加的函数体,而main.c中调用add函数:
/*filename:add.h*/
externint
add(inti,intj);
/*filename:add.c*/
int
add(inti,intj)
{
returni+j;
}
/*filename:main.c*/
#include"add.h"
main()
{
inta,b;
a=2;
b=3;
printf("thesumofa+bis%d",add(a+b));}怎样为上述三个文件产生makefile呢?4.Make为上述三个文件产生makefile的方法如下:
test:main.o
add.o
gcc
main.o
add.o-otest
main.o:main.c
add.h
gcc-cmain.c-omain.o
add.o:add.c
add.h
gcc-cadd.c-oadd.o
4.Make上述makefile文件的含义利用add.c和add.h文件执行gcc-cadd.c-oadd.o命令产生add.o目标代码。利用main.c和add.h文件执行gcc-cmain.c-omain.o命令产生main.o目标代码。最后利用main.o和add.o文件(两个模块的目标代码)执行gcc
main.o
add.o-otest命令产生可执行文件test。可以使用gcc-MMmain.c自动寻找源文件中的头文件,并形成依赖关系。输出为:main.o
main.c
add.h4.Make可在makefile中加入变量。另外,环境变量在make过程中也被解释成make的变量。这些变量是大小写敏感的,一般使用大写字母。要定义一个变量,只需要在一行的开始写下这个变量的名字,后面跟一个=号,再跟变量的值。引用变量的方法是写一个$符号,后面跟(变量名)。4.Make把前面的makefile
利用变量重写一遍(并假设使用-Wall-O–g编译选项):OBJS=main.o
add.oCC=gccCFLAGS=-Wall-O-gtest:$(OBJS)$(CC)$(OBJS)-otestmain.o:main.c
add.h$(CC)$(CFLAGS)-cmain.c-omain.oadd.o:add.c
add.h$(CC)$(CFLAGS)-cadd.c-oadd.o
4.Makemakefile
中还可定义清除(clean)目标,可用来清除编译过程中产生的中间文件,例如在上述makefile文件中添加下列代码:clean:
rm-f*.o运行makeclean时,将执行rm-f*.o命令,删除所有编译过程中产生的中间文件。
4.MakeMake的运行GUNmake默认在当前的目录下一次查找GUNmake文件,Makefile文件和makefile文件,找到后读取文件执行。给make命令指定一个特殊名字的makefile文件make–fhchen.mk4.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.c
configure.in
Makefile.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(constchar*filename,mode_tmode);
参数mode指定新建文件的存取权限,它同umask一起决定文件的最终权限(mode&umask).umask代表了文件在创建时需要去掉的一些存取权限。umask可通过系统调用umask()来改变:
int
umask(int
newmask);
该调用将umask设置为newmask,然后返回旧的umask,它只影响读、写和执行权限。1.Linux文件API-创建mode可以是以下情况的组合,可以通过上述宏进行“或”逻辑产生标志。
标志含义S_IRUSR
用户可以读
S_IWUSR
用户可以写
S_IXUSR
用户可以执行
S_IRWXU
用户可以读、写、执行
S_IRGRP
组可以读
S_IWGRP组可以写S_IXGRP组可以执行S_IRWXG组可以读写执行1.Linux文件API-创建mode可以是以下情况的组合,可以通过上述宏进行“或”逻辑产生标志。标志含义S_IROTH其他人可以读S_IWOTH其他人可以写S_IXOTH其他人可以执行S_IRWXO其他人可以读、写、执行S_ISUID设置用户执行IDS_ISGID设置组的执行ID1.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(constchar*pathname,intflags);int
open(constchar*pathname,intflags,mode_tmode);如果文件打开成功,open函数会返回一个文件描述符,以后对该文件的所有操作就可以通过对这个文件描述符进行操作来实现。open函数有两个形式,其中pathname是要打开的文件名(包含路径名称,缺省是认为在当前路径下面)。
1.Linux文件API-打开打开flags可以是下面的一个值或者是几个值的组合,O_RDONLY、O_WRONLY、O_RDWR三个标志只能使用任意的一个。1.Linux文件API-打开打开如果使用了O_CREATE标志,则使用的函数是int
open(constchar*pathname,int
flags,mode_tmode);这时要指定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,constvoid*buf,size_tlength);
int
write(int
fd,constvoid*buf,size_tlength);参数buf为指向缓冲区的指针,length为缓冲区的大小(以字节为单位)。1.Linux文件API-读写int
read(int
fd,constvoid*buf,size_tlength);函数read实现从文件描述符fd所指定的文件中读取length个字节到buf所指向的缓冲区中,返回值为实际读取的字节数。int
write(int
fd,constvoid*buf,size_tlength);函数write实现将把length个字节从buf指向的缓冲区中写到文件描述符fd所指向的文件中,返回值为实际写入的字节数。1.Linux文件API-定位定位:对于随机文件,我们可以随机的指定位置读写,使用如下函数进行定位:
int
lseek(int
fd,offset_toffset,intwhence);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,softwareweekly”,关闭该文件。再次打开该文件,读取其中的内容并输出在屏幕上。
#include<sys/types.h>//类型#include<sys/stat.h>//获取文件属性#include<fcntl.h>//文件描述词操作#include<stdio.h>
#defineLENGTH100
main()
{
int
fd,len;
charstr[LENGTH];
fd=open(“hello.txt”,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);/*创建并打开文件,以读写的方式打开,用户可以读、用户可以写*/
1.Linux文件API-编程实例if(fd)
{
write(fd,"Hello,SoftwareWeekly",strlen("Hello,softwareweekly"));/*写入Hello,softwareweekly字符串*/
close(fd);
}
fd=open(“hello.txt”,O_RDWR);//以读写方式打开
len=read(fd,str,LENGTH);/*读取文件内容*/
str[len]='\0';
printf("%s\n",str);
close(fd);
}1.Linux文件API-编程实例1.Linux文件API-编程实例编译并运行,执行结果如下[root@dl
root]#gcc–g–ohello./hello.c[root@dlroot]#./helloHello,softwareweekly
3.C语言库函数C库函数的文件操作实际上是独立于具体的操作系统平台的,不管是在DOS、Windows、Linux还是在VxWorks中都是这些函数.
3.C语言库函数-创建和打开创建和打开FILE*fopen(constchar*path,constchar*mode);fopen()实现打开指定文件,参数path字符串包含欲打开的文件路径及文件名
,mode为打开模式.返回值:文件指针名。必须被说明为FILE类型的指针变量。3.C语言库函数-创建和打开C语言中支持的打开模式如下表,其中b用于区分二进制文件和文本文件,在DOS、Windows系统中是有区分的,但Linux不区分二进制文件和文本文件。
标志含义r,rb以只读方式打开w,wb以只写方式打开。如果文件不存在,则创建该文件,否则文件被截断a,ab以追加方式打开。如果文件不存在,则创建该文件r+,r+b,rb+以读写方式打开+,w+b,wh+以读写方式打开。如果文件不存在时,创建新文件,否则文件被截断a+,a+b,ab+以读和追加方式打开。如果文件不存在,创建新文件3.C语言库函数-读写读写:C库函数支持以字符、字符串等为单位,支持按照某中格式进行文件的读写,这一组函数为:int
fgetc(FILE*stream);从流中读一个字符int
fputc(intc,FILE*stream);送一个字符到流中char*fgets(char*s,intn,FILE*stream);从流中读取一字符串
int
fputs(constchar*s,FILE*stream);送一个字符串到流中3.C语言库函数-读写int
fprintf(FILE*stream,constchar*format,...);传送格式化输出到一个文件中,成功时返回转换的字节数,失败时返回一个负数。
fprintf(stream,"%s%c",s,c);
fprintf(stream,"%d\n",i);int
fscanf(FILE*stream,constchar*format,...);从一个流中执行格式化输入
if(fscanf(stdin,"%d",&i))
printf("Theintegerreadwas:%d\n",i);
3.C语言库函数-读写读写:size_t
fread(void*ptr,size_tsize,size_tn,FILE*stream);size_t
fwrite(constvoid*ptr,size_tsize,size_tn,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,constfpos_t*pos);//将文件指针定位在pos指定的位置上返回值:成功返回0,否则返回非0。#include<stdio.h>voidmain(void){FILE*fp;
fpos_tpos;charbuffer[50];if((fp=fopen("test.txt","rb"))==NULL)/*以只读方式打开名为test.txt的文件*/
printf("Troubleopeningfile\n");else{pos=10;/*设置pos值*/if(fsetpos(fp,&pos)!=0)/*应用fsetpos函数将文件指针fp按照pos指定的位置在文件中定位*/
perror("fsetposerror");else{
/*从新定位的文件指针开始读取16个字符到buffer缓冲区*/fread(buffer,sizeof(char),16,fp);printf("16bytesatbyte%ld:%.16s\n",pos,buffer);/*显示结果*/}}
fclose(fp);}
3.C语言库函数-定位首先,程序以只读方式打开名为test.txt的文件。在这里,test.txt文件中已存入字符串Thisisatestfortestingthefunctionoffsetpos.将pos设置为10。应用fsetpos函数将文件指针fp按照pos指定的位置在文件中定位。这样文件指针fp指向字符串中test的字母t。再从新定位的文件指针开始读取16个字符到buffer缓冲区,也就是说读取字符串"testfortesting"到缓冲区buffer。最后显示结果:16bytesatbyte10:testfortesting
3.C语言库函数-定位int
fseek(FILE*stream,longoffset,intwhence);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,softwareweekly”,关闭该文件。再次打开该文件,读取其中的内容并输出在屏幕上。
#include<stdio.h>
#defineLENGTH100
main()
{
FILE*fd;
charstr[LENGTH];
fd=fopen("hello.txt","w+");/*创建并打开文件*/
if(fd)
{
fputs("Hello,SoftwareWeekly",fd);/*写入Hello,softwareweekly字符串*/
fclose(fd);
}
fd=fopen("hello.txt","r");
fgets(str,LENGTH,fd);/*读取文件内容*/
printf("%s\n",str);
fclose(fd);
}3.小结Linux提供的虚拟文件系统为多种文件系统提供了统一的接口,Linux的文件编程有两种途径:基于Linux系统调用;基于C库函数这两种编程所涉及到文件操作有新建、打开、读写和关闭,对随机文件还可以定位。
第二部分
Linux下的C编程实战之进程控制与进程通信编程1.进程的基本概念进程是具有一定功能的程序,是关于一个数据集合的一次执行过程。多个进程可以同时运行。Linux进程在内存中包含三部分数据:代码段:存放了程序的代码,代码段可以为机器中运行同一程序的数个进程共享。堆栈段:存放的是子程序(函数)的返回地址、子程序的参数及程序的局部变量。数据段:存放程序的全局变量、常数以及动态数据分配的数据空间。堆栈段和数据段不能为运行同一程序的数个进程共享。2.进程控制-进程的创建(1)派生进程系统调用fork用于派生一个进程,其说明如下:
#include<unistd.h>
pid_t
fork(void);
pid_t
vfork(void);调用fork时,系统创建一个与当前进程(父进程)相同的新进程(子进程)。子进程是父进程的一个复制,子进程拷贝父进程的数据段、代码段2.进程控制-进程的创建fork调用将执行两次返回,它将从父进程和子进程中分别返回。从父进程返回时的返回值为子进程的PID,而从子进程返回时的返回值为0,并且返回都将执行fork之后的语句。调用出错时,返回值为-1#include<sys/types.h>#include<stdio.h>#include<unistd.h>intmain(){
pid_t
pid;
pid=fork();
if((pid)<0){
printf(“forkerror!\n”);exit(1);}elseif(pid=0)
printf(“childprocessisprinting.IDis%d\n”,getpid());else
printf(“parentprocessisprinting.IDis%d\n”,getpid());}拷贝代码段的实例运行结果:
[root@lwm
liweimeng]#gccfork1.c-ofork1
[root@lwm
liweimeng]#./fork1
Iamthechildprocess,IDis4238
Iamtheparentprocess,IDis4237因为fork()函数用于从已存在的进程中创建一个新的子进程,在pid=fork();语句之前只有父进程在运行,而在之后,父进程和新创建的子进程都在运行,子进程拷贝父进程的代码段,所以子进程中同样有
if(pid<0)printf("errorinfork!");
elseif(pid==0)
printf("Iamthechildprocess,IDis%d\n",getpid());
else
printf("Iamtheparentprocess,IDis%d\n",getpid());2.进程控制-进程的创建#include<unistd.h>#include<unistd.h>intmain(){
pid_t
pid;
Intcount=0;
pid=fork();
Count++;
Printf(“count=%d\n”,count);Return0;}输出:Count=1Count=1拷贝数据段的实例将被父子进程各执行一次,但是子进程执行时使自己的数据段里面的(这个数据段是从父进程那copy过来的一模一样)count+1,同样父进程执行时使自己的数据段里面count+1,互不影响2.进程控制-进程的创建vfork的作用和fork基本相同,区别在于:vfork并不完全复制父进程的数据段,而是和父进程共享数据段。调用vfork对于父子进程的执行次序有所限制。调用vfork函数将使父进程挂起,直至子进程返回。vfork
保证子进程先运行,在她调用exec或exit之后父进程才可能被调度运行。#include<unistd.h>
#include<stdio.h>
#include<sys/types.h>
int
main(void)
{
pid_t
pid;
intcount=0;
pid=vfork();
if(pid==0)
{
count++;
_exit(0);}
else
count++;
printf("count=%d\n",count);return0;
}2.进程控制-进程的创建在子进程调用exec或exit之前与父进程数据是共享的,所以子进程退出后把父进程的数据段count改成1了,子进程退出后,父进程又执行,最终就将count变成了2运行结果:
[root@lwm
liweimeng]#gccfork2.c-ofork2
[root@lwm
liweimeng]#./fork2
count=22.进程控制-进程的创建(2)创建执行其他程序的进程使用exec族的函数执行新的程序,以新的子进程完全替代原有的进程。int
execl(constchar*pathname,constchar*arg,…);int
execlp(constchar*filename,conxtchar*arg,…);int
execle(constchar*pathname,conxtchar*arg,…,char#constencp[]);int
execv(constchar*pathname,char*constargv[]);int
execvp(constchar*filename,char*constargv[]);int
execve(constchar*pathname,char*constargv[],char*constenvp[]);2.进程控制-进程的创建exec函数族的特点用于启动一个指定路径和文件名的进程。某进程一旦调用了exec类函数,正在执行的程序结束,系统把代码段换成新的程序的代码,原有的数据段和堆栈段也被放弃,新的数据段和堆栈段被分配,但是进程号被保留。结果为:系统认为正在执行的还是原来的进程,但是进程对应的程序被替换了。2.进程控制-进程的创建fork和exec搭配实现让父进程的代码执行又启动一个新的指定的进程。execl()使用范例#include<stdio.h>#include<unistd.h>#include<sys/types.h>main(){
pid_t
pid;
printf("Nowonlyoneprocess\n");
printf("Callingfork...\n");
pid=fork();
if(pid==0)/*进程为子进程*/{
printf("Iamthechild\n");
execl("/bin/ls","-l",NULL);
/*如果execl返回,说明调用失败*/
perror("execlfailedtorunls");exit(1);}2.进程控制-进程的创建elseif(pid>0)/*进程为父进程*/ {
printf("I'mtheparent,mychild'spidis%d\n",pid);
execl("/bin/ps","-c",NULL);/*如果execl返回,说明调用失败*/
perror("execlfailedtorunls");exit(1);}else
printf("Forkfall!\n");}2.进程控制-进程的创建Clone此函数是fork的变形,对父子进程的共享资源提供了更多的控制。可以使得创建的子进程共享父进程的资源。函数原型:int
clone(int(*fn)(void),void*child_stack,int
flags,void*arg)fn是函数指针,指向要执行的函数child_stack子进程堆栈段的指针flags用于不同继承内容的标识2.进程控制-进程的创建Flags标识含义CLONE_VM继承父进程的虚拟存储器属性CLONE_FS继承父进程的chroot
chdir
和umaskCLONE_FILES继承父进程的文件描述符CLONE_PID继承父进程的文件锁、进程号及时间片CLONE_SIGHAND继承父进程的信号处理程序Flags标识的选取2.进程控制-进程的创建intvariable,fd;
int
do_something(){
variable=42;
close(fd);
_exit(0);
}
2.进程控制-进程的创建int
main(int
argc,char*argv[]){
void**child_stack;
chartempch;
variable=9;
fd=open("test.file",O_RDONLY);
child_stack=(void**)malloc(16384);
printf("Thevariablewas%d\n",variable);
clone(do_something,child_stack,CLONE_VM|CLONE_FILES,NULL);
sleep(1);/*延时以便子进程完成关闭文件操作、修改变量*/
2.进程控制-进程的创建printf("Thevariableisnow%d\n",variable);
if(read(fd,&tempch,1)<1){
perror("FileReadError");
exit(1);
}
printf("Wecouldreadfromthefile\n");
return0;
}2.进程控制-进程的创建运行输出:
Thevariableisnow42
FileReadError
程序的输出结果说明,子进程将文件关闭并将变量修改(调用clone时用到的CLONE_VM、CLONE_FILES标志将使得变量和文件描述符表被共享),父进程随即就感觉到了,这就是clone的特点。
2.进程控制-进程的挂起Sleep函数调用sleep可以用来使进程挂起指定的秒数。如果指定的挂起的时间到了,该调用的返回值为0;如果该函数调用被信号打断,则返回剩余挂起的时间数(指定的时间减去已经挂起的时间)函数原型unsignedint
sleep(unsigned
intseconds)2.进程控制-进程的等待WaitWait的作用是为发出调用的进程只要有子进程,就睡眠到他们中的一个终止为止。函数原型pid_t
wait(int*status);
//子进程的结束状态值会由参数status返回
pid_t
waitpid(pid_t
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年浙江嘉兴平湖市卫生健康系统赴浙江中医药大学招聘在编卫生专业技术人员28人笔试核心备考题库及答案解析
- 2024年度建筑装饰工程设计合同
- 2024年度合作研发合同及技术保密协议
- 2024年度瓷砖企业战略规划与经营目标合同
- 2024年度版权许可合同:汽车音乐版权许可协议3篇
- 2024年度服务合同标的为商务咨询2篇
- 2024中外合作经营合同
- 2024年度版权质押合同全新协议
- 2024个人简单装修合同范本
- 《粘膜硬化加固治疗降低食管静脉曲张复发疗效及机制研究》
- GB 40165-2021固定式电子设备用锂离子电池和电池组安全技术规范
- 深圳市失业人员停止领取失业保险待遇申请表空表
- DJI 产品交付理论试题
- 公开课-诫子书-一等奖-完整课件
- 《中国当代文艺思潮》导论文艺思潮的基本概念
- 2023年南方出版传媒股份有限公司招聘笔试模拟试题及答案解析
- 初中语文阅读专题教学课件
- 危险化学品安全经营单位主要负责人和安全管理人员培课件
- 综合实践活动教师评价表家长评价表、学生评价表
- 教育调查研究课件
- 人物访谈类栏目课件
评论
0/150
提交评论