




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
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.outgcchelloworld.co選項:編譯來為將產生的可執行文件指定一個文件名。例如,將上述名為helloworld.c的C程序編譯為名叫helloworld的可執行文件,輸入如下命令:gcc-ohelloworldhelloworld.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*/
externintadd(inti,intj);
/*filename:add.c*/
intadd(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.oadd.o
gccmain.oadd.o-otest
main.o:main.cadd.h
gcc-cmain.c-omain.o
add.o:add.cadd.h
gcc-cadd.c-oadd.o4.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文件〔兩個模塊的目標代碼〕執行gccmain.oadd.o-otest命令產生可執行文件test。可以使用gcc-MMmain.c自動尋找源文件中的頭文件,并形成依賴關系。輸出為:main.omain.cadd.h4.Make可在makefile中參加變量。另外,環境變量在make過程中也被解釋成make的變量。這些變量是大小寫敏感的,一般使用大寫字母。要定義一個變量,只需要在一行的開始寫下這個變量的名字,后面跟一個=號,再跟變量的值。引用變量的方法是寫一個$符號,后面跟〔變量名〕。4.Make把前面的makefile利用變量重寫一遍〔并假設使用-Wall-O–g編譯選項〕:OBJS=main.oadd.oCC=gccCFLAGS=-Wall-O-gtest:$(OBJS)$(CC)$(OBJS)-otestmain.o:main.cadd.h$(CC)$(CFLAGS)-cmain.c-omain.oadd.o:add.cadd.h$(CC)$(CFLAGS)-cadd.c-oadd.o4.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;./helloworldMakefile被產生出來,而且可以將helloworld.c編譯通過。小結本局部主要闡述了Linux程序的編寫、編譯、調試方法及make,實際上是引導學習怎樣在Linux下編程,為后續章節做好準備。
第二局部Linux下的C編程實戰之文件系統編程Linux平臺下文件編程在Linux平臺下對文件編程可以使用兩類函數:Linux操作系統文件API;C語言I/O庫函數。前者依賴于Linux系統調用,后者實際上與操作系統是獨立的,因為在任何操作系統下,使用C語言I/O庫函數操作文件的方法都是相同的。1.Linux文件API-創立創立intcreate(constchar*filename,mode_tmode);參數mode指定新建文件的存取權限,它同umask一起決定文件的最終權限〔mode&umask).umask代表了文件在創立時需要去掉的一些存取權限。umask可通過系統調用umask()來改變:intumask(intnewmask);該調用將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-翻開翻開intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);如果文件翻開成功,open函數會返回一個文件描述符,以后對該文件的所有操作就可以通過對這個文件描述符進行操作來實現。open函數有兩個形式,其中pathname是要翻開的文件名(包含路徑名稱,缺省是認為在當前路徑下面)。
1.Linux文件API-翻開翻開flags可以是下面的一個值或者是幾個值的組合,O_RDONLY、O_WRONLY、O_RDWR三個標志只能使用任意的一個。1.Linux文件API-翻開翻開如果使用了O_CREATE標志,那么使用的函數是intopen(constchar*pathname,intflags,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函數:intread(intfd,constvoid*buf,size_tlength);intwrite(intfd,constvoid*buf,size_tlength);參數buf為指向緩沖區的指針,length為緩沖區的大小〔以字節為單位〕。1.Linux文件API-讀寫intread(intfd,constvoid*buf,size_tlength);函數read實現從文件描述符fd所指定的文件中讀取length個字節到buf所指向的緩沖區中,返回值為實際讀取的字節數。intwrite(intfd,constvoid*buf,size_tlength);函數write實現將把length個字節從buf指向的緩沖區中寫到文件描述符fd所指向的文件中,返回值為實際寫入的字節數。1.Linux文件API-定位定位:對于隨機文件,我們可以隨機的指定位置讀寫,使用如下函數進行定位:intlseek(intfd,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是要關閉的文件描述符:
intclose(intfd);1.Linux文件API-編程實例例程:編寫一個程序,在當前目錄下創立用戶可讀寫文件“hello.txt”,在其中寫入“Hello,softwareweekly”,關閉該文件。再次翻開該文件,讀取其中的內容并輸出在屏幕上。
#include<sys/types.h>//類型#include<sys/stat.h>//獲取文件屬性#include<fcntl.h>//文件描述詞操作#include<stdio.h>
#defineLENGTH100
main()
{
intfd,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@dlroot]#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庫函數支持以字符、字符串等為單位,支持按照某中格式進行文件的讀寫,這一組函數為:intfgetc(FILE*stream);從流中讀一個字符intfputc(intc,FILE*stream);送一個字符到流中char*fgets(char*s,intn,FILE*stream);從流中讀取一字符串
intfputs(constchar*s,FILE*stream);送一個字符串到流中3.C語言庫函數-讀寫intfprintf(FILE*stream,constchar*format,...);傳送格式化輸出到一個文件中,成功時返回轉換的字節數,失敗時返回一個負數。
fprintf(stream,"%s%c",s,c);
fprintf(stream,"%d\n",i);intfscanf(FILE*stream,constchar*format,...);從一個流中執行格式化輸入if(fscanf(stdin,"%d",&i))printf("Theintegerreadwas:%d\n",i);
3.C語言庫函數-讀寫讀寫:size_tfread(void*ptr,size_tsize,size_tn,FILE*stream);size_tfwrite(constvoid*ptr,size_tsize,size_tn,FILE*stream);fread()實現從流stream中讀取n個字段,每個字段為size字節,并將讀取的字段放入ptr所指的字符數組中,返回實際已讀取的字段數。write()實現從緩沖區ptr所指的數組中把n個字段寫到流stream中,每個字段長為size個字節,返回實際寫入的字段數。3.C語言庫函數-定位定位:C庫函數還提供了讀寫過程中的定位能力,這些函數包括:intfgetpos(FILE*stream,fpos_t*pos);//將文件流的文件位置指示符存儲在pos變量中intfsetpos(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:testfortesting3.C語言庫函數-定位intfseek(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庫函數關閉文件的操作:
intfclose(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_tfork(void);pid_tvfork(void);調用fork時,系統創立一個與當前進程〔父進程〕相同的新進程〔子進程〕。子進程是父進程的一個復制,子進程拷貝父進程的數據段、代碼段2.進程控制-進程的創立fork調用將執行兩次返回,它將從父進程和子進程中分別返回。從父進程返回時的返回值為子進程的PID,而從子進程返回時的返回值為0,并且返回都將執行fork之后的語句。調用出錯時,返回值為-1#include<sys/types.h>#include<stdio.h>#include<unistd.h>intmain(){pid_tpid;pid=fork();
if((pid)<0){printf(“forkerror!\n”);exit(1);}elseif(pid=0)printf(“childprocessisprinting.IDis%d\n”,getpid());elseprintf(“parentprocessisprinting.IDis%d\n”,getpid());}拷貝代碼段的實例運行結果:
[root@lwmliweimeng]#gccfork1.c-ofork1
[root@lwmliweimeng]#./fork1
Iamthechildprocess,IDis4238
Iamtheparentprocess,IDis4237因為fork〔〕函數用于從已存在的進程中創立一個新的子進程,在pid=fork();語句之前只有父進程在運行,而在之后,父進程和新創立的子進程都在運行,子進程拷貝父進程的代碼段,所以子進程中同樣有
if(pid<0)printf("errorinfork!");
elseif(pid==0)
printf("Iamthechildprocess,IDis%d\n",getpid());
elseprintf("Iamtheparentprocess,IDis%d\n",getpid());2.進程控制-進程的創立#include<unistd.h>#include<unistd.h>intmain(){pid_tpid;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>
intmain(void)
{
pid_tpid;
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@lwmliweimeng]#gccfork2.c-ofork2
[root@lwmliweimeng]#./fork2
count=22.進程控制-進程的創立〔2〕創立執行其他程序的進程使用exec族的函數執行新的程序,以新的子進程完全替代原有的進程。intexecl(constchar*pathname,constchar*arg,…);intexeclp(constchar*filename,conxtchar*arg,…);intexecle(constchar*pathname,conxtchar*arg,…,char#constencp[]);intexecv(constchar*pathname,char*constargv[]);intexecvp(constchar*filename,char*constargv[]);intexecve(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_tpid;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);}elseprintf("Forkfall!\n");}2.進程控制-進程的創立Clone此函數是fork的變形,對父子進程的共享資源提供了更多的控制。可以使得創立的子進程共享父進程的資源。函數原型:intclone(int(*fn)(void),void*child_stack,intflags,void*arg)fn是函數指針,指向要執行的函數child_stack子進程堆棧段的指針flags用于不同繼承內容的標識2.進程控制-進程的創立Flags標識含義CLONE_VM繼承父進程的虛擬存儲器屬性CLONE_FS繼承父進程的chrootchdir和umaskCLONE_FILES繼承父進程的文件描述符CLONE_PID繼承父進程的文件鎖、進程號及時間片CLONE_SIGHAND繼承父進程的信號處理程序Flags標識的選取2.進程控制-進程的創立intvariable,fd;
intdo_something(){
variable=42;
close(fd);
_exit(0);
}
2.進程控制-進程的創立intmain(intargc,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;如果該函數調用被信號打斷,那么返回剩余掛起的時間數〔指定的時間減去已經掛起的時間〕函數原型unsignedintsleep(unsignedintseconds)2.進程控制-進程的等待WaitWait的作用是為發出調用的進程只要有子進程,就睡眠到他們中的一個終止為止。函數原型pid_twait(int*status);
//子進程的結束狀態值會由參數status返回
pid_twaitpid(pid_tpid,int*status,intoptions);//子進程的結束狀態值會由參數status返回,而子
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- YY 0459-2025外科植入物丙烯酸類樹脂骨水泥
- 新疆北庭希望環保科技有限公司吉木薩爾縣25萬噸-年危廢處理利用項目(2)環評報告
- 某著名企業DeepSeek系列09DeepSeek政務應用場景與解決方案
- 工業廢水處理與綠色工藝技術
- 工業廢氣治理技術與方法探討
- 工業大數據的分析與應用
- 工業建筑設計及自動化機電系統
- 工業污染防治與綠色制造技術分析
- 工業網絡通信協議與技術標準
- 工業生產中的設備優化管理
- 2025年北京豐臺區九年級中考二模英語試卷試題(含答案詳解)
- 新生兒收治流程規范與實施
- T/CBMCA 017-2021建筑用覆膜鋼板
- 《重癥監護病房的臨終關懷和姑息治療指南》解讀
- 2025年初中地理會考試卷
- 中國鈦基復合材料行業市場前景預測及投資價值評估分析報告
- 2024年江蘇省無錫市中考歷史真題(原卷版)
- 三級營養師考試復習重點題(附答案)
- 重慶市沙坪壩區2023-2024學年四年級下學期語文期末試卷(含答案)
- 安全領導力與執行力經典培訓課件
- 四年級數學下冊 六 運算律第4課時 乘法的分配律教學設計 蘇教版
評論
0/150
提交評論