淺析若何在c說話中挪用Linux劇本。本站提示廣大學習愛好者:(淺析若何在c說話中挪用Linux劇本)文章只能為提供參考,不一定能成為您想要的結果。以下是淺析若何在c說話中挪用Linux劇本正文
1、引言
關於沒有接觸過Unix/Linux操作體系的人來講,fork是最難懂得的概念之一:它履行一次卻前往兩個值。fork函數是Unix體系最出色的造詣之一,它是七十年月UNIX晚期的開辟者經由歷久在實際和理論上的艱難摸索後獲得的結果,一方面,它使操作體系在過程治理上支付了最小的價值,另外一方面,又為法式員供給了一個簡練清楚明了的多過程辦法。與DOS和晚期的Windows分歧,Unix/Linux體系是真正完成多義務操作的體系,可以說,不應用多過程編程,就不克不及算是真實的Linux情況下編程。
多線程法式設計的概念早在六十年月就被提出,但直到八十年月中期,Unix體系中才引入多線程機制,現在,因為本身的很多長處,多線程編程曾經獲得了普遍的運用。
上面,我們將引見在Linux下編寫多過程和多線程法式的一些初步常識。
2、多過程編程
甚麼是一個過程?過程這個概念是針對體系而不是針對用戶的,對用戶來講,他面臨的概念是法式。當用戶敲入敕令履行一個法式的時刻,對體系而言,它將啟動一個過程。但和法式分歧的是,在這個過程中,體系能夠須要再啟動一個或多個過程來完成自力的多個義務。多過程編程的重要內容包含過程掌握和過程間通訊,在懂得這些之前,我們先要簡略曉得過程的構造。
2.1 Linux下過程的構造
Linux下一個過程在內存裡有三部門的數據,就是"代碼段"、"客棧段"和"數據段"。其實學過匯編說話的人必定曉得,普通的CPU都有上述三種段存放器,以便利操作體系的運轉。這三個部門也是組成一個完全的履行序列的需要的部門。
"代碼段",望文生義,就是寄存了法式代碼的數據,假設機械中稀有個過程運轉雷同的一個法式,那末它們便可以應用雷同的代碼段。"客棧段"寄存的就是子法式的前往地址、子法式的參數和法式的部分變量。而數據段則寄存法式的全局變量,常數和靜態數據分派的數據空間(好比用malloc之類的函數獲得的空間)。這個中有很多細節成績,這裡限於篇幅就不多引見了。體系假如同時運轉數個雷同的法式,它們之間就不克不及應用統一個客棧段和數據段。
2.2 Linux下的過程掌握
在傳統的Unix情況下,有兩個根本的操感化於創立和修正過程:函數fork( )用來創立一個新的過程,該過程簡直是以後過程的一個完整拷貝;函數族exec( )用來啟動別的的過程以代替以後運轉的過程。Linux的過程掌握和傳統的Unix過程掌握根本分歧,只在一些細節的處所有些差別,例如在Linux體系中挪用vfork和fork完整雷同,而在有些版本的Unix體系中,vfork挪用有分歧的功效。因為這些差異簡直不影響我們年夜多半的編程,在這裡我們不予斟酌。
2.2.1 fork()
fork在英文中是"分叉"的意思。為何取這個名字呢?由於一個過程在運轉中,假如應用了fork,就發生了另外一個過程,因而過程就"分叉"了,所以這個名字獲得很抽象。上面就看看若何詳細應用fork,這段法式演示了應用fork的根本框架:
void main()
{
int i;
if ( fork() == 0 )
{
/* 子過程法式 */
for ( i = 1; i <1000; i ++ )
printf("This is child process\n");
}
else
{
/* 父過程法式*/
for ( i = 1; i <1000; i ++ )
printf("This is process process\n");
}
}
法式運轉後,你就可以看到屏幕上瓜代湧現子過程與父過程各打印出的一千條信息了。假如法式還在運轉中,你用ps敕令就可以看到體系中有兩個它在運轉了。
那末挪用這個fork函數時產生了甚麼呢?fork函數啟動一個新的過程,後面我們說過,這個過程簡直是以後過程的一個拷貝:子過程和父過程應用雷同的代碼段;子過程復制父過程的客棧段和數據段。如許,父過程的一切數據都可以留給子過程,然則,子過程一旦開端運轉,固然它繼續了父過程的一切數據,但現實上數據卻曾經離開,互相之間不再有影響了,也就是說,它們之間不再同享任何數據了。它們再要交互信息時,只要經由過程過程間通訊來完成,這將是我們上面的內容。既然它們如斯相象,體系若何來辨別它們呢?這是由函數的前往值來決議的。關於父過程, fork函數前往了子法式的過程號,而關於子法式,fork函數則前往零。在操作體系中,我們用ps函數便可以看到分歧的過程號,對父過程而言,它的過程號是由比它更低層的體系挪用付與的,而關於子過程而言,它的過程號等於fork函數對父過程的前往值。在法式設計中,父過程和子過程都要挪用函數fork()上面的代碼,而我們就是應用fork()函數對父子過程的分歧前往值用if...else...語句來完成讓父子過程完成分歧的功效,正如我們下面舉的例子一樣。我們看到,下面例子履行時兩條信息是交互無規矩的打印出來的,這是父子過程自力履行的成果,固然我們的代碼仿佛和串行的代碼沒有甚麼差別。
讀者或許會問,假如一個年夜法式在運轉中,它的數據段和客棧都很年夜,一次fork就要復制一次,那末fork的體系開支不是很年夜嗎?其實UNIX自有其處理的方法,年夜家曉得,普通CPU都是以"頁"為單元來分派內存空間的,每個頁都是現實物理內存的一個映像,象INTEL的CPU,其一頁在平日情形下是 4086字節年夜小,而不管是數據段照樣客棧段都是由很多"頁"組成的,fork函數復制這兩個段,只是"邏輯"上的,並不是"物理"上的,也就是說,現實履行fork時,物理空間上兩個過程的數據段和客棧段都照樣同享著的,當有一個過程寫了某個數據時,這時候兩個過程之間的數據才有了差別,體系就將有差別的" 頁"從物理上也離開。體系在空間上的開支便可以到達最小。
上面演示一個足以"弄逝世"Linux的小法式,其源代碼異常簡略:
void main()
{
for( ; ; )
{
fork();
}
}
這個法式甚麼也不做,就是逝世輪回地fork,其成果是法式赓續發生過程,而這些過程又赓續發生新的過程,很快,體系的過程就滿了,體系就被這麼多赓續發生 的過程"撐逝世了"。固然只需體系治理員事後給每一個用戶設置可運轉的最年夜過程數,這個歹意的法式就完成不了妄圖了。
2.2.2 exec( )函數族
上面我們來看看一個過程若何來啟動另外一個法式的履行。在Linux中要應用exec函數族。體系挪用execve()對以後過程停止調換,調換者為一個指定的法式,其參數包含文件名(filename)、參數列表(argv)和情況變量(envp)。exec函數族固然不止一個,但它們年夜致雷同,在 Linux中,它們分離是:execl,execlp,execle,execv,execve和execvp,上面我只以execlp為例,其它函數畢竟與execlp有何差別,請經由過程manexec敕令來懂得它們的詳細情形。
一個過程一旦挪用exec類函數,它自己就"逝世亡"了,體系把代碼段調換成新的法式的代碼,放棄原本的數據段和客棧段,並為新法式分派新的數據段與客棧段,獨一留下的,就是過程號,也就是說,對體系而言,照樣統一個過程,不外曾經是另外一個法式了。(不外exec類函數中有的還許可繼續情況變量之類的信息。)
那末假如我的法式想啟動另外一法式的履行但本身仍想持續運轉的話,怎樣辦呢?那就是聯合fork與exec的應用。上面一段代碼顯示若何啟動運轉其它法式:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
char command[256];
void main()
{
int rtn; /*子過程的前往數值*/
while(1) {
/* 從終端讀取要履行的敕令 */
printf( ">" );
fgets( command, 256, stdin );
command[strlen(command)-1] = 0;
if ( fork() == 0 ) {/* 子過程履行此敕令 */
execlp( command, NULL );
/* 假如exec函數前往,注解沒有正常履行敕令,打印毛病信息*/
perror( command );
exit( errno );
}
else {/* 父過程, 期待子過程停止,並打印子過程的前往值 */
wait ( &rtn );
printf( " child process return %d\n", rtn );
}
}
}
此法式從終端讀入敕令並履行之,履行完成後,父過程持續期待從終端讀入敕令。熟習DOS和WINDOWS體系挪用的同伙必定曉得DOS/WINDOWS也有exec類函數,其應用辦法是相似的,但DOS/WINDOWS還有spawn類函數,由於DOS是單義務的體系,它只能將"父過程"駐留在機械內再履行"子過程",這就是spawn類的函數。WIN32曾經是多義務的體系了,但還保存了spawn類函數,WIN32中完成spawn函數的辦法同前述 UNIX中的辦法差不多,開設子過程後父過程期待子過程停止後才持續運轉。UNIX在其一開端就是多義務的體系,所以從焦點角度上講不須要spawn類函數。
在這一節裡,我們還要講講system()和popen()函數。system()函數先挪用fork(),然後再挪用exec()來履行用戶的登錄 shell,經由過程它來查找可履行文件的敕令並剖析參數,最初它麼應用wait()函數族之一來期待子過程的停止。函數popen()和函數 system()類似,分歧的是它挪用pipe()函數創立一個管道,經由過程它來完成法式的尺度輸出和尺度輸入。這兩個函數是為那些不太勤勞的法式員設計的,在效力和平安方面都有相當的缺點,在能夠的情形下,應當盡可能防止。