欧美一区二区三区四区视频|久久久久久88色偷偷|国产精品视频一区二区三区w|国产综合色在线视频|久久久久久综合七次郎|好硬好紧好湿进去了好爽

合肥做網(wǎng)站,選擇瘋狗科技,專(zhuān)業(yè)、敬業(yè)的合肥網(wǎng)絡(luò )公司
首頁(yè) > 網(wǎng)站技術(shù) > 詳情

如何在c語(yǔ)言中調用Linux腳本

2017-12-25 16:10:40   來(lái)源:互聯(lián)網(wǎng)   瀏覽:  次
如何在c語(yǔ)言中調用Linux腳本呢?你知道如何在c語(yǔ)言中調用Linux腳本嗎?下面是小編為大家帶來(lái)的如何在c語(yǔ)言中調用Linux腳本的知識,歡迎閱讀。

如何在c語(yǔ)言中調用Linux腳本呢?你知道如何在c語(yǔ)言中調用Linux腳本嗎?下面是小編為大家帶來(lái)的如何在c語(yǔ)言中調用Linux腳本的知識,歡迎閱讀。

一、引言

對于沒(méi)有接觸過(guò)Unix/Linux操作系統的人來(lái)說(shuō),fork是最難理解的概念之一:它執行一次卻返回兩個(gè)值。fork函數是Unix系統最杰出的成就之一,它是七十年代UNIX早期的開(kāi)發(fā)者經(jīng)過(guò)長(cháng)期在理論和實(shí)踐上的艱苦探索后取得的成果,一方面,它使操作系統在進(jìn)程管理上付出了最小的代價(jià),另一方面,又為程序員提供了一個(gè)簡(jiǎn)潔明了的多進(jìn)程方法。與DOS和早期的Windows不同,Unix/Linux系統是真正實(shí)現多任務(wù)操作的系統,可以說(shuō),不使用多進(jìn)程編程,就不能算是真正的Linux環(huán)境下編程。多線(xiàn)程程序設計的概念早在六十年代就被提出,但直到八十年代中期,Unix系統中才引入多線(xiàn)程機制,如今,由于自身的許多優(yōu)點(diǎn),多線(xiàn)程編程已經(jīng)得到了廣泛的應用。下面,我們將介紹在Linux下編寫(xiě)多進(jìn)程和多線(xiàn)程程序的一些初步知識。

二、多進(jìn)程編程

什么是一個(gè)進(jìn)程?進(jìn)程這個(gè)概念是針對系統而不是針對用戶(hù)的,對用戶(hù)來(lái)說(shuō),他面對的概念是程序。當用戶(hù)敲入命令執行一個(gè)程序的時(shí)候,對系統而言,它將啟動(dòng)一個(gè)進(jìn)程。但和程序不同的是,在這個(gè)進(jìn)程中,系統可能需要再啟動(dòng)一個(gè)或多個(gè)進(jìn)程來(lái)完成獨立的多個(gè)任務(wù)。多進(jìn)程編程的主要內容包括進(jìn)程控制和進(jìn)程間通信,在了解這些之前,我們先要簡(jiǎn)單知道進(jìn)程的結構。

2.1 Linux下進(jìn)程的結構

Linux下一個(gè)進(jìn)程在內存里有三部分的數據,就是“代碼段”、“堆棧段”和“數據段”。其實(shí)學(xué)過(guò)匯編語(yǔ)言的人一定知道,一般的CPU都有上述三種段寄存器,以方便操作系統的運行。這三個(gè)部分也是構成一個(gè)完整的執行序列的必要的部分。

“代碼段”,顧名思義,就是存放了程序代碼的數據,假如機器中有數個(gè)進(jìn)程運行相同的一個(gè)程序,那么它們就可以使用相同的代碼段。“堆棧段”存放的就是子程序的返回地址、子程序的參數以及程序的局部變量。而數據段則存放程序的全局變量,常數以及動(dòng)態(tài)數據分配的數據空間(比如用malloc之類(lèi)的函數取得的空間)。這其中有許多細節問(wèn)題,這里限于篇幅就不多介紹了。系統如果同時(shí)運行數個(gè)相同的程序,它們之間就不能使用同一個(gè)堆棧段和數據段。

2.2 Linux下的進(jìn)程控制

在傳統的Unix環(huán)境下,有兩個(gè)基本的操作用于創(chuàng )建和修改進(jìn)程:函數fork( )用來(lái)創(chuàng )建一個(gè)新的進(jìn)程,該進(jìn)程幾乎是當前進(jìn)程的一個(gè)完全拷貝;函數族exec( )用來(lái)啟動(dòng)另外的進(jìn)程以取代當前運行的進(jìn)程。Linux的進(jìn)程控制和傳統的Unix進(jìn)程控制基本一致,只在一些細節的地方有些區別,例如在Linux系統中調用vfork和fork完全相同,而在有些版本的Unix系統中,vfork調用有不同的功能。由于這些差別幾乎不影響我們大多數的編程,在這里我們不予考慮

2.2.1 fork()

fork在英文中是“分叉”的意思。為什么取這個(gè)名字呢?因為一個(gè)進(jìn)程在運行中,如果使用了fork,就產(chǎn)生了另一個(gè)進(jìn)程,于是進(jìn)程就“分叉”了,所以這個(gè)名字取得很形象。下面就看看如何具體使用fork,這段程序演示了使用fork的基本框架

代碼如下:

void main()

{

int i;

if ( fork() == 0 )

{

/* 子進(jìn)程程序 */

for ( i = 1; i <1000; i ++ )

printf(“This is child process ”);

}

else

{

/* 父進(jìn)程程序*/

for ( i = 1; i <1000; i ++ )

printf(“This is process process ”);

}

}

程序運行后,你就能看到屏幕上交替出現子進(jìn)程與父進(jìn)程各打印出的一千條信息了。如果程序還在運行中,你用ps命令就能看到系統中有兩個(gè)它在運行了。

那么調用這個(gè)fork函數時(shí)發(fā)生了什么呢?fork函數啟動(dòng)一個(gè)新的進(jìn)程,前面我們說(shuō)過(guò),這個(gè)進(jìn)程幾乎是當前進(jìn)程的一個(gè)拷貝:子進(jìn)程和父進(jìn)程使用相同的代碼段;子進(jìn)程復制父進(jìn)程的堆棧段和數據段。這樣,父進(jìn)程的所有數據都可以留給子進(jìn)程,但是,子進(jìn)程一旦開(kāi)始運行,雖然它繼承了父進(jìn)程的一切數據,但實(shí)際上數據卻已經(jīng)分開(kāi),相互之間不再有影響了,也就是說(shuō),它們之間不再共享任何數據了。它們再要交互信息時(shí),只有通過(guò)進(jìn)程間通信來(lái)實(shí)現,這將是我們下面的內容。既然它們如此相象,系統如何來(lái)區分它們呢?這是由函數的返回值來(lái)決定的。對于父進(jìn)程, fork函數返回了子程序的進(jìn)程號,而對于子程序,fork函數則返回零。在操作系統中,我們用ps函數就可以看到不同的進(jìn)程號,對父進(jìn)程而言,它的進(jìn)程號是由比它更低層的系統調用賦予的,而對于子進(jìn)程而言,它的進(jìn)程號即是fork函數對父進(jìn)程的返回值。在程序設計中,父進(jìn)程和子進(jìn)程都要調用函數fork()下面的代碼,而我們就是利用fork()函數對父子進(jìn)程的不同返回值用if…else…語(yǔ)句來(lái)實(shí)現讓父子進(jìn)程完成不同的功能,正如我們上面舉的例子一樣。我們看到,上面例子執行時(shí)兩條信息是交互無(wú)規則的打印出來(lái)的,這是父子進(jìn)程獨立執行的結果,雖然我們的代碼似乎和串行的代碼沒(méi)有什么區別。

讀者也許會(huì )問(wèn),如果一個(gè)大程序在運行中,它的數據段和堆棧都很大,一次fork就要復制一次,那么fork的系統開(kāi)銷(xiāo)不是很大嗎?其實(shí)UNIX自有其解決的辦法,大家知道,一般CPU都是以“頁(yè)”為單位來(lái)分配內存空間的,每一個(gè)頁(yè)都是實(shí)際物理內存的一個(gè)映像,象INTEL的CPU,其一頁(yè)在通常情況下是 4086字節大小,而無(wú)論是數據段還是堆棧段都是由許多“頁(yè)”構成的,fork函數復制這兩個(gè)段,只是“邏輯”上的,并非“物理”上的,也就是說(shuō),實(shí)際執行fork時(shí),物理空間上兩個(gè)進(jìn)程的數據段和堆棧段都還是共享著(zhù)的,當有一個(gè)進(jìn)程寫(xiě)了某個(gè)數據時(shí),這時(shí)兩個(gè)進(jìn)程之間的數據才有了區別,系統就將有區別的“ 頁(yè)”從物理上也分開(kāi)。系統在空間上的開(kāi)銷(xiāo)就可以達到最小。下面演示一個(gè)足以“搞死”Linux的小程序,其源代碼非常簡(jiǎn)單。代碼如下:

void main()

{

for( ; ; )

{

fork();

}

}

這個(gè)程序什么也不做,就是死循環(huán)地fork,其結果是程序不斷產(chǎn)生進(jìn)程,而這些進(jìn)程又不斷產(chǎn)生新的進(jìn)程,很快,系統的進(jìn)程就滿(mǎn)了,系統就被這么多不斷產(chǎn)生 的進(jìn)程“撐死了”。當然只要系統管理員預先給每個(gè)用戶(hù)設置可運行的最大進(jìn)程數,這個(gè)惡意的程序就完成不了企圖了。

2.2.2 exec( )函數族

下面我們來(lái)看看一個(gè)進(jìn)程如何來(lái)啟動(dòng)另一個(gè)程序的執行。在Linux中要使用exec函數族。系統調用execve()對當前進(jìn)程進(jìn)行替換,替換者為一個(gè)指定的程序,其參數包括文件名(filename)、參數列表(argv)以及環(huán)境變量(envp)。exec函數族當然不止一個(gè),但它們大致相同,在 Linux中,它們分別是:execl,execlp,execle,execv,execve和execvp,下面我只以execlp為例,其它函數究竟與execlp有何區別,請通過(guò)manexec命令來(lái)了解它們的具體情況。一個(gè)進(jìn)程一旦調用exec類(lèi)函數,它本身就“死亡”了,系統把代碼段替換成新的程序的代碼,廢棄原有的數據段和堆棧段,并為新程序分配新的數據段與堆棧段,唯一留下的,就是進(jìn)程號,也就是說(shuō),對系統而言,還是同一個(gè)進(jìn)程,不過(guò)已經(jīng)是另一個(gè)程序了。(不過(guò)exec類(lèi)函數中有的還允許繼承環(huán)境變量之類(lèi)的信息。)那么如果我的程序想啟動(dòng)另一程序的執行但自己仍想繼續運行的話(huà),怎么辦呢?那就是結合fork與exec的使用。下面一段代碼顯示如何啟動(dòng)運行其它程序:

代碼如下:

#include

#include

#include

char command[256];

void main()

{

int rtn; /*子進(jìn)程的返回數值*/

while(1) {

/* 從終端讀取要執行的命令 */

printf( “>” );

fgets( command, 256, stdin );

command[strlen(command)-1] = 0;

if ( fork() == 0 ) {/* 子進(jìn)程執行此命令 */

execlp( command, NULL );

/* 如果exec函數返回,表明沒(méi)有正常執行命令,打印錯誤信息*/

perror( command );

exit( errno );

}

else {/* 父進(jìn)程, 等待子進(jìn)程結束,并打印子進(jìn)程的返回值 */

wait ( &rtn );

printf( “ child process return %d ”, rtn );

}

}

}

此程序從終端讀入命令并執行之,執行完成后,父進(jìn)程繼續等待從終端讀入命令。熟悉DOS和WINDOWS系統調用的朋友一定知道DOS/WINDOWS也有exec類(lèi)函數,其使用方法是類(lèi)似的,但DOS/WINDOWS還有spawn類(lèi)函數,因為DOS是單任務(wù)的系統,它只能將“父進(jìn)程”駐留在機器內再執行“子進(jìn)程”,這就是spawn類(lèi)的函數。WIN32已經(jīng)是多任務(wù)的系統了,但還保留了spawn類(lèi)函數,WIN32中實(shí)現spawn函數的方法同前述 UNIX中的方法差不多,開(kāi)設子進(jìn)程后父進(jìn)程等待子進(jìn)程結束后才繼續運行。UNIX在其一開(kāi)始就是多任務(wù)的系統,所以從核心角度上講不需要spawn類(lèi)函數。在這一節里,我們還要講講system()和popen()函數。system()函數先調用fork(),然后再調用exec()來(lái)執行用戶(hù)的登錄 shell,通過(guò)它來(lái)查找可執行文件的命令并分析參數,最后它么使用wait()函數族之一來(lái)等待子進(jìn)程的結束。函數popen()和函數 system()相似,不同的是它調用pipe()函數創(chuàng )建一個(gè)管道,通過(guò)它來(lái)完成程序的標準輸入和標準輸出。這兩個(gè)函數是為那些不太勤快的程序員設計的,在效率和安全方面都有相當的缺陷,在可能的情況下,應該盡量避免。

欧美一区二区三区四区视频|久久久久久88色偷偷|国产精品视频一区二区三区w|国产综合色在线视频|久久久久久综合七次郎|好硬好紧好湿进去了好爽