C語言建立子程序

2021-10-13 09:57:43 字數 4603 閱讀 3254

程式執行的時候,可以建立與自己關聯的子程序,建立了這個子程序之後,可以選擇等待這個子程序執行完畢,也可以讓子程序與自己並行執行,還可以終止自己轉而執行子程序。這些操作都是通過一系列相似而又有細微區別的庫函式來實現。下面對這些可以使用的庫函式進行介紹。

它的函式定義如下:

#include int system(const char * string);
這個程序會在系統中另外啟動乙個shell,並在新的shell中執行引數string給定的命令。如果無法啟動shell,這個函式會返回127錯誤碼,其他錯誤返回-1,否則返回該命令的退出碼。

在程式中呼叫這個函式之後,呼叫程序會等待新shell中命令執行完成,之後在繼續執行。但是也可以在string引數的命令後面加上&讓命令後台執行,這樣就能實現呼叫程序與新shell程序並行執行。

下面是乙個例子:

#include #include int main(void)
編譯並執行上面的程式會得到下面的輸出:

now running a new process.

f s uid pid ppid c pri ni addr sz wchan tty time cmd

0 s 1000 5691 5646 0 80 0 - 581762 poll_s pts/0 00:00:04 vim

0 s 1000 6424 6215 0 80 0 - 570 do_wai pts/1 00:00:00 a

0 s 1000 6425 6424 0 80 0 - 598 do_wai pts/1 00:00:00 sh

0 r 1000 6426 6425 0 80 0 - 2897 - pts/1 00:00:00 ps

returned from the sub process.

可以看到程式執行到一半時,建立了乙個子程序ps,等到子程序執行完畢,才回到自己的程式繼續執行。

如果在執行的命令ps -al後面加上&,就會讓子程式後台執行,從而呼叫程式與子程式就能並行執行。

上面的system()需要啟動乙個新shell,並在新的shell中執行子程式,這樣做的執行效率不高,並且因為不同的環境shell版本不一樣,所以也會造成相容性的問題。因此我們在需要建立子程序的時候使用exec系列函式,而不是system()

exec系列函式的作用都是結束本程式的執行,轉而執行另外乙個程式。新建立的子程式整合了原來程序的資源,有著同樣的pid

新的程式預設狀態下會繼承已開啟的檔案,但是如果檔案使用fcntl()開啟並且設定了fd_cloexec,則執行新程序的時候會關閉檔案。

下面是所有exec系列函式的定義:

int execl(const char *pathname, const char *arg, ...)

int execv(const char *pathname, char *const ar**)

int execle(const char *pathname, const char *arg, ..., char *const envp)

int execve(const char *pathname, char *const ar**, char *const envp)

int execlp(const char *filename, const char *arg, ...)

int execvp(const char *filename, char *const ar**)

其中檔名的不同表示了傳遞引數的方式,查詢程式的方式以及是否可以設定環境變數不同。對於名字的前四個字母exec都是統一的函式名,後面跟上l表示按照引數列表的方式接受多個函式引數;v表示利用字串陣列來接受多個引數;p表示系統將通過搜尋path環境變數來查詢程式;e表示可以傳入環境變數。

下面是乙個使用exec系列函式從當前程序啟動ps程式的例子,在這個例子中使用了上面的所有方法:

#include #include int main(void);	//就算使用陣列的形式傳入引數,也要用0表示引數的結尾

char * const ps_envp = ;

//下面的函式只有第乙個可以執行,剩餘的只是作為演示

execl("/bin/ps", "blahhh", "-al", 0);

//剩下的函式不會被執行

execlp("ps", "ps", "-af", 0);

execle("/bin/ps", "ps", "-af", 0, ps_envp);

execv("/bin/ps", ps_ar**);

execvp("ps", ps_ar**);

execve("/bin/ps", ps_ar**, ps_envp);

}

關於這個程式,有幾個需要注意的地方:

使用fork()函式可以複製當前的程序。新建立的程序與原來的程序幾乎完全一樣,但是兩個程序都有自己的資料,環境和檔案描述符。並且新建立的程序是當前程序的子程序,基於這個特性,可以使用fork()先建立乙個與當前程序一模一樣的子程序,然後使用exec()函式使子程序轉而執行另乙個程式,就可以使另外乙個子程序成為當前程序的子程序。

如果子程序建立失敗,fork()函式會返回-1,並且將錯誤碼儲存在errno中,如果呼叫成功則返回子程序的pid。因為子程序跟父程序執行的**相同,所以在子程序中也會有乙個fork()函式,但是子程序中的fork()函式不會建立另外乙個子程序,因為如果這樣就會無限迴圈下去,取而代之子程序的fork()函式不會建立任何子程序,同時返回0,可以用這一點來判斷當前程序是乙個父程序還是乙個子程序。下面是乙個例子:

#include #include int main(void)

return 0;

}

當使用fork()函式建立乙個子程序之後,子程序與父程序是並行執行的,如果想將父程序掛起知道子程序執行結束,可以使用wait()函式。這個函式會讓父程序等待到子程序執行完畢之後在繼續執行。當子程序結束之後,這個函式會返回子程序的pid,並且會將子程序返回的狀態碼儲存到指定位置stat_loc,指定的位置只需要乙個整型變數即可。

下面是該函式的定義:

#include #include pid_t wait(int *stat_loc);
函式返回的狀態資訊被儲存在乙個整型數里,這個資料不是人能看得懂的,如果要檢視子程序結束時的狀態,可以使用sys/wait.h中定義的巨集來實現,常用的巨集有:巨集說明

wifexited(stat_val)

如果子程序正常結束,它就取乙個非零值

wexitstatus(stat_val)

如果子程序正常結束,返回子程序的退出碼

wifsignaled(stat_val)

如果子程序因為乙個未捕獲的訊號終止,返回非零值

wtermsig(stat_val)

如果子程序因為乙個未捕獲的訊號終止,返回訊號**

wifstopped(stat_val)

如果子程序意外終止,返回乙個非零值

wstopsig(stat_val)

如果子程序意外終止,返回乙個訊號**

下面是乙個例子:

#include #include #include #include int main(void)

return 0;

}

這個函式有另外乙個加強版本,它會讓程式等待另外任意乙個程式執行完畢。它的定義為:

#include #include pid_t waitpid(pid_t pid, int * stat_loc, int options);
這個函式的返回值跟wait()函式一樣,但是引數卻不一樣,pid表示要等待的程序的pidstat_loc表示要儲存程序返回狀態的地方,options是用於控制該函式行為的選項,其中乙個常用的選項是wnohang,它的作用是防止呼叫程式在等待另乙個程序的時候被掛起。

linux c建立子程序

前言 了解fork 函式 乙個程序呼叫fork 函式建立該程序子程序,系統會為該子程序分配資源儲存資料和 的空間,父程序將資料和 複製給子程序,子程序按父程序 重新執行,即轉殖了父程序並重新執行。fork 函式的返回值,1即fork失敗,值為0時即子程序,返回值大於0即子程序id c 樣例 incl...

linux建立子程序

include include include intmain int argc,char ar else if pid 0 else if pid 0 return0 include include include intmain int argc,char ar else if pid 0 el...

Unix建立子程序

fork函式用於在已存在程序中新建程序。fork函式呼叫一次,返回兩次。當fork返回值為0時,當前程序為fork函式建立的子程序 當fork函式返回值大於0時,當前程序與fork函式呼叫前的程序一致,我們稱之為父程序 當fork函式返回值為 1時,fork函式建立子程序失敗。系統無法保證父程序與子...