




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
精品文檔-下載后可編輯Linux下的多進(jìn)程編程-基礎(chǔ)電子(一)理解Linux下進(jìn)程的結(jié)構(gòu)
Linux下一個(gè)進(jìn)程在內(nèi)存里有三部份的數(shù)據(jù),就是“數(shù)據(jù)段”,“堆棧段”和“代碼段”,其實(shí)學(xué)過匯編語言的人一定知道,一般的CPU象I386,都有上述三種段寄存器,以方便操作系統(tǒng)的運(yùn)行?!按a段”,顧名思義,就是存放了程序代碼的數(shù)據(jù),假如機(jī)器中有數(shù)個(gè)進(jìn)程運(yùn)行相同的一個(gè)程序,那么它們就可以使用同一
個(gè)代碼段。
堆棧段存放的就是子程序的返回地址、子程序的參數(shù)以及程序的局部變量。而數(shù)據(jù)段則存放程序的全局變量,常數(shù)以及動(dòng)態(tài)數(shù)據(jù)分配的數(shù)據(jù)空間(比如用malloc之類的函數(shù)取得的空間)。這其中有許多細(xì)節(jié)問題,這里限于篇幅就不多介紹了。系統(tǒng)如果同時(shí)運(yùn)行數(shù)個(gè)相同的程序,它們之間就不能使用同一個(gè)堆棧段和數(shù)據(jù)段。
(二)如何使用fork
在Linux下產(chǎn)生新的進(jìn)程的系統(tǒng)調(diào)用就是fork函數(shù),這個(gè)函數(shù)名是英文中“分叉”的意思。為什么取這個(gè)名字呢?因?yàn)橐粋€(gè)進(jìn)程在運(yùn)行中,如果使用了fork,就產(chǎn)生了另一個(gè)進(jìn)程,于是進(jìn)程就“分叉”了,所以這個(gè)名字取得很形象。下面就看看如何具體使用fork,這段程序演示了使用fork的基本框架:
voidmain(){
inti;
if(fork()==0){
/*子進(jìn)程程序*/
for(i=1;i1000;i)
printf("Thisischildprocess\n");
}
else{
/*父進(jìn)程程序*/
for(i=1;i1000;i)
printf("Thisisprocessprocess\n");
}
}
程序運(yùn)行后,你就能看到屏幕上交替出現(xiàn)子進(jìn)程與父進(jìn)程各打印出的一千條信息了。如果程序還在運(yùn)行中,你用ps命令就能看到系統(tǒng)中有兩個(gè)它在運(yùn)行了。
那么調(diào)用這個(gè)fork函數(shù)時(shí)發(fā)生了什么呢?一個(gè)程序一調(diào)用fork函數(shù),系統(tǒng)就為一個(gè)新的進(jìn)程準(zhǔn)備了前述三個(gè)段,首先,系統(tǒng)讓新的進(jìn)程與舊的進(jìn)程使用同一個(gè)代碼段,因?yàn)樗鼈兊某绦蜻€是相同的,對(duì)于數(shù)據(jù)段和堆棧段,系統(tǒng)則復(fù)制一份給新的進(jìn)程,這樣,父進(jìn)程的所有數(shù)據(jù)都可以留給子進(jìn)程,但是,子進(jìn)程一旦開始運(yùn)行,雖然它繼承了父進(jìn)程的一切數(shù)據(jù),但實(shí)際上數(shù)據(jù)卻已經(jīng)分開,相互之間不再有影響了,也就是說,它們之間不再共享任何數(shù)據(jù)了。而如果兩個(gè)進(jìn)程要共享什么數(shù)據(jù)的話,就要使用另一套函數(shù)(shmget,shmat,shmdt等)來操作?,F(xiàn)在,已經(jīng)是兩個(gè)進(jìn)程了,對(duì)于父進(jìn)程,fork函數(shù)返回了子程序的進(jìn)程號(hào),而對(duì)于子程序,fork函數(shù)則返回零,這樣,對(duì)于程序,只要判斷fork函數(shù)的返回值,就知道自己是處于父進(jìn)程還是子進(jìn)程中。
讀者也許會(huì)問,如果一個(gè)大程序在運(yùn)行中,它的數(shù)據(jù)段和堆棧都很大,fork就要復(fù)制,那么fork的系統(tǒng)開銷不是很大嗎?其實(shí)UNIX自有其解決的辦法,大家知道,一般CPU都是以“頁”為單位分配空間的,象INTEL的CPU,其一頁在通常情況下是4K字節(jié)大小,而無論是數(shù)據(jù)段還是堆棧段都是由許多“頁”構(gòu)成的,fork函數(shù)復(fù)制這兩個(gè)段,只是“邏輯”上的,并非“物理”上的,也就是說,實(shí)際執(zhí)行fork時(shí),物理空間上兩個(gè)進(jìn)程的數(shù)據(jù)段和堆棧段都還是共享著的,當(dāng)有一個(gè)進(jìn)程寫了某個(gè)數(shù)據(jù)時(shí),這時(shí)兩個(gè)進(jìn)程之間的數(shù)據(jù)才有了區(qū)別,系統(tǒng)就將有區(qū)別的“頁”從物理上也分開。系統(tǒng)在空間上的開銷就可以達(dá)到。
一個(gè)小幽默:下面演示一個(gè)足以"搞死"Linux的小程序,其源代碼非常簡(jiǎn)單:
voidmain()
{
for(;;)fork();
}
這個(gè)程序什么也不做,就是死循環(huán)地fork,其結(jié)果是程序不斷產(chǎn)生進(jìn)程,而這些進(jìn)程又不斷產(chǎn)生新的進(jìn)程,很快,系統(tǒng)的進(jìn)程就滿了,系統(tǒng)就被這么多不斷產(chǎn)生的進(jìn)程"撐死了"。用不著是root,任何人運(yùn)行上述程序都足以讓系統(tǒng)死掉。哈哈,但這不是Linux不安全的理由,因?yàn)橹灰到y(tǒng)管理員足夠聰明,他(或她)就可以預(yù)先給每個(gè)用戶設(shè)置可運(yùn)行的進(jìn)程數(shù),這樣,只要不是root,任何能運(yùn)行的進(jìn)程數(shù)也許不足系統(tǒng)總的能運(yùn)行和進(jìn)程數(shù)的十分之一,這樣,系統(tǒng)管理員就能對(duì)付上述惡意的程序了。
(三)如何啟動(dòng)另一程序的執(zhí)行
下面我們來看看一個(gè)進(jìn)程如何來啟動(dòng)另一個(gè)程序的執(zhí)行。在Linux中要使用exec類的函數(shù),exec類的函數(shù)不止一個(gè),但大致相同,在Linux中,它們分別是:execl,execlp,execle,execv,execve和execvp,下面我只以execlp為例,其它函數(shù)究竟與execlp有何區(qū)別,請(qǐng)通過manexec命令來了解它們的具體情況。
一個(gè)進(jìn)程一旦調(diào)用exec類函數(shù),它本身就“死亡”了,系統(tǒng)把代碼段替換成新的程序的代碼,廢棄原有的數(shù)據(jù)段和堆棧段,并為新程序分配新的數(shù)據(jù)段與堆棧段,留下的,就是進(jìn)程號(hào),也就是說,對(duì)系統(tǒng)而言,還是同一個(gè)進(jìn)程,不過已經(jīng)是另一個(gè)程序了。(不過exec類函數(shù)中有的還允許繼承環(huán)境變量之類的信息。)
那么如果我的程序想啟動(dòng)另一程序的執(zhí)行但自己仍想繼續(xù)運(yùn)行的話,怎么辦呢?那就是結(jié)合fork與exec的使用。下面一段代碼顯示如何啟動(dòng)運(yùn)行其它程序:
charcommand[256];
voidmain()
{
intrtn;/*子進(jìn)程的返回?cái)?shù)值*/
while(1){
/*從終端讀取要執(zhí)行的命令*/
printf("");
fgets(command,256,stdin);
command[strlen(command)-1]=0;
if(fork()==0){
/*子進(jìn)程執(zhí)行此命令*/
execlp(command,command);
/*如果exec函數(shù)返回,表明沒有正常執(zhí)行命令,打印錯(cuò)誤信息*/
perror(command);
exit(errorno);
}
else{
/*父進(jìn)程,等待子進(jìn)程結(jié)束,并打印子進(jìn)程的返回值*/
wait(rtn);
printf("childprocessreturn%d\n",.rtn);
}
}
}
此程序從終端讀入命令并執(zhí)行之,執(zhí)行完成后,父進(jìn)程繼續(xù)等待從終端讀入命令。熟悉DOS和WINDOWS系統(tǒng)調(diào)用的朋友一定知道DOS/WINDOWS也有exec類函數(shù),其使用方法是類似的,但DOS/WINDOWS還有spawn類函數(shù),因?yàn)镈OS是單任務(wù)的系統(tǒng),它只能將“父進(jìn)程”駐留在機(jī)器內(nèi)再執(zhí)行“子進(jìn)程”,這就是spawn類的函數(shù)。WIN32已經(jīng)是多任務(wù)的系統(tǒng)了,但還保留了spawn類函數(shù),WIN32中實(shí)現(xiàn)spawn函數(shù)的方法同前述UNIX中的方法差不多,開設(shè)子進(jìn)程后父進(jìn)程等待子進(jìn)程結(jié)束后才繼續(xù)運(yùn)行。UNIX在其一開始就是多任務(wù)的系統(tǒng),所以從核心角度上講不需要spawn類函數(shù)。
另外,有一個(gè)更簡(jiǎn)單的執(zhí)行其它程序的函數(shù)system,它是一個(gè)較高層的函數(shù),實(shí)際上相當(dāng)于在SHELL環(huán)境下執(zhí)行一條命令,而exec類函數(shù)則是低層的系統(tǒng)調(diào)用。
(四)Linux的進(jìn)程與Win32的進(jìn)程/線程有何區(qū)別
熟悉WIN32編程的人一定知道,WIN32的進(jìn)程管理方式與UNIX上有著很大區(qū)別,在UNIX里,只有進(jìn)程的概念,但在WIN32里卻還有一個(gè)“線程”的概念,那么UNIX和WIN32在這里究竟有著什么區(qū)別呢?
UNIX里的fork是七十年代UNIX早期的開發(fā)者經(jīng)過長(zhǎng)期在理論和實(shí)踐上的艱苦探索后取得的成果,一方面,它使操作系統(tǒng)在進(jìn)程管理上付出了的代價(jià),另一方面,又為程序員提供了一個(gè)簡(jiǎn)潔明了的多進(jìn)程方法。
WIN32里的進(jìn)程/線程是繼承自O(shè)S/2的。在WIN32里,“進(jìn)程”是指一個(gè)程序,而“線程”是一個(gè)“進(jìn)程”里的一個(gè)執(zhí)行“線索”。從上講,WIN32的多進(jìn)程與UNIX并無多大的區(qū)別,在WIN32里的線程才相當(dāng)于UNIX的進(jìn)程,是一個(gè)實(shí)際正在執(zhí)行的代碼。但是,WIN32里同一個(gè)進(jìn)程里各個(gè)線程之間是共享數(shù)據(jù)段的。這才是與UNIX的進(jìn)程的不同。
下面這段程序顯示了WIN32下一個(gè)進(jìn)程如何啟動(dòng)一個(gè)線程:(請(qǐng)注意,這是個(gè)終端方式程序,沒有圖形界面)
intg;
DWORDWINAPIChildProcess(LPVOIDlpParameter){
inti;
for(i=1;i1000;i){
g;
printf("ThisisChildThread:%d\n",g);
}
ExitThread(0);
};
voidmain()
{
intthreadID;
inti;
g=0;
CreateThread(NULL,0,ChildProcess,NULL,0,threadID);
for(i=1;i1000;i){
g;
printf("ThisisParentThread:%d\n",g);
}
}
在WIN32下,使用CreateThread函數(shù)創(chuàng)建線程,與UNIX不同,線程不是從創(chuàng)建處開始運(yùn)行的,而是由CreateThread指定一個(gè)函數(shù),線程就從那個(gè)函數(shù)處開始運(yùn)行。此程序同前面的UNIX程序一樣,由兩個(gè)線程各打印1000條信息。threadID是子線程的線程號(hào),另外,全局變量g是子線程與父線程共享的,這就是與UNIX的不同之處。大家可以看出,WIN32的進(jìn)程/線程要比UNIX復(fù)雜,在UNIX里要實(shí)現(xiàn)類似WIN32的線程并不難,只要fork以后,讓子進(jìn)程調(diào)用ThreadProc函數(shù),并且為全局變量開設(shè)共享數(shù)據(jù)區(qū)就行了,但在WIN32下就無法實(shí)現(xiàn)類似fork的功能了。所以現(xiàn)在WIN32下的C語言編譯器所提供的庫函數(shù)雖然已經(jīng)能兼容大多數(shù)UNIX的庫函數(shù),但卻仍無法實(shí)現(xiàn)fork。
對(duì)于多任務(wù)系統(tǒng),共享數(shù)據(jù)區(qū)是必要的,但也是一個(gè)容易引起混亂的問題,在WIN32下,一個(gè)程序員很容易忘記線程之間的數(shù)據(jù)是共享的這一情況,一個(gè)線程修改過一個(gè)變量后,另一個(gè)線程卻又修改了它,結(jié)果引起程序出問題。但在UNI
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- emc買斷合同范本
- 代款合作合同范本
- 2025年抗風(fēng)濕類藥品合作協(xié)議書
- 合同范本網(wǎng)翻譯
- 合同范本全是正式合同
- 雙方交付款合同范例
- 2025年分離純化控制系統(tǒng)項(xiàng)目合作計(jì)劃書
- 中英日文合同范本
- 合同范本模板去石墻
- 叉車置換銷售合同范本
- Unit5 What day is it today?(教學(xué)設(shè)計(jì))-2023-2024學(xué)年教科版(廣州)英語四年級(jí)下冊(cè)
- 《網(wǎng)絡(luò)信息安全教學(xué)》課件
- 徐州2025年江蘇徐州市口腔醫(yī)院招聘非在編醫(yī)務(wù)人員53人筆試歷年參考題庫附帶答案詳解-1
- 2025年01月2025中國作家協(xié)會(huì)所屬單位公開招聘11人筆試歷年典型考題(歷年真題考點(diǎn))解題思路附帶答案詳解
- 影視制作項(xiàng)目委托制作協(xié)議
- 用色彩情感引發(fā)共鳴社交媒體運(yùn)營秘訣
- 廣東2024年12月佛山市教育局公開選調(diào)1名公務(wù)員筆試歷年典型考題(歷年真題考點(diǎn))解題思路附帶答案詳解
- 植物角創(chuàng)設(shè)培訓(xùn)
- 法院生活費(fèi)申請(qǐng)書
- 2025年湖南工藝美術(shù)職業(yè)學(xué)院高職單招職業(yè)技能測(cè)試近5年??及鎱⒖碱}庫含答案解析
- 2025年江西機(jī)電職業(yè)技術(shù)學(xué)院高職單招職業(yè)技能測(cè)試近5年常考版參考題庫含答案解析
評(píng)論
0/150
提交評(píng)論