欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux啟動(dòng)新進(jìn)程的幾種方法及比較

 更新時(shí)間:2017年04月27日 16:04:57   作者:ljianhui  
有時(shí)候,我們需要在自己的程序(進(jìn)程)中啟動(dòng)另一個(gè)程序(進(jìn)程)來(lái)幫助我們完成一些工作,那么我們需要怎么才能在自己的進(jìn)程中啟動(dòng)其他的進(jìn)程呢?在Linux中提供了不少的方法來(lái)實(shí)現(xiàn)這一點(diǎn),下面就來(lái)介紹一個(gè)這些方法及它們之間的區(qū)別。

有時(shí)候,我們需要在自己的程序(進(jìn)程)中啟動(dòng)另一個(gè)程序(進(jìn)程)來(lái)幫助我們完成一些工作,那么我們需要怎么才能在自己的進(jìn)程中啟動(dòng)其他的進(jìn)程呢?在Linux中提供了不少的方法來(lái)實(shí)現(xiàn)這一點(diǎn),下面就來(lái)介紹一個(gè)這些方法及它們之間的區(qū)別。

一、system函數(shù)調(diào)用

system函數(shù)的原型為:

#include <stdlib.h> 
int system (const char *string); 

它的作用是,運(yùn)行以字符串參數(shù)的形式傳遞給它的命令并等待該命令的完成。命令的執(zhí)行情況就如同在shell中執(zhí)行命令:sh -c string。如果無(wú)法啟動(dòng)shell來(lái)運(yùn)行這個(gè)命令,system函數(shù)返回錯(cuò)誤代碼127;如果是其他錯(cuò)誤,則返回-1。否則,system函數(shù)將返回該命令的退出碼。

注意:system函數(shù)調(diào)用用一個(gè)shell來(lái)啟動(dòng)想要執(zhí)行的程序,所以可以把這個(gè)程序放到后臺(tái)中執(zhí)行,這里system函數(shù)調(diào)用會(huì)立即返回。

可以先先下面的例子,源文件為new_ps_system.c,代碼如下:

#include <stdlib.h> 
#include <stdio.h> 
int main() 
{ 
  printf("Running ps with system\n"); 
  //ps進(jìn)程結(jié)束后才返回,才能繼續(xù)執(zhí)行下面的代碼 
  system("ps au");// 1 
  printf("ps Done\n"); 
  exit(0); 
} 

該程序調(diào)用ps程序打印所有與本用戶有關(guān)的進(jìn)程,最后才打印ps Done。運(yùn)行結(jié)果如下:

如果把注釋1的語(yǔ)句改為:system("ps au &");則system函數(shù)立即返回,不用等待ps進(jìn)程結(jié)束即可執(zhí)行下面的代碼。所以你看到的輸出,ps Done可能并不是出現(xiàn)在最后一行,而是在中間。

一般來(lái)說(shuō),使用system函數(shù)不是啟動(dòng)其他進(jìn)程的理想手段,因?yàn)樗仨氂靡粋€(gè)shell來(lái)啟動(dòng)需要的程序,即在啟動(dòng)程序之前需要先啟動(dòng)一個(gè)shell,而且對(duì)shell的環(huán)境的依賴也很大,因此使用system函數(shù)的效率不高。

二、替換進(jìn)程映像——使用exec系列函數(shù)

exec系列函數(shù)由一組相關(guān)的函數(shù)組成,它們?cè)谶M(jìn)程的啟動(dòng)方式和程序參數(shù)的表達(dá)方式上各有不同。但是exec系列函數(shù)都有一個(gè)共同的工作方式,就是把當(dāng)前進(jìn)程替換為一個(gè)新進(jìn)程,也就是說(shuō)你可以使用exec函數(shù)將程序的執(zhí)行從一個(gè)程序切換到另一個(gè)程序,在新的程序啟動(dòng)后,原來(lái)的程序就不再執(zhí)行了,新進(jìn)程由path或file參數(shù)指定。exec函數(shù)比system函數(shù)更有效。

exec系列函數(shù)的類型為:

#include <unistd.h> 

char **environ; 

int execl (const char *path, const char *arg0, ..., (char*)0); 
int execlp(const char *file, const char *arg0, ..., (char*)0); 
int execle(const char *path, const char *arg0, ..., (char*)0, char *const envp[]); 
int execv (const char *path, char *const argv[]); 
int execvp(cosnt char *file, char *const argv[]); 
int execve(const char *path, char *const argv[], char *const envp[]); 

這類函數(shù)可以分為兩大類,execl、execlp和execle的參數(shù)是可變的,以一個(gè)空指針結(jié)束,而execv、execvp和execve的第二個(gè)參數(shù)是一個(gè)字符串?dāng)?shù)組,在調(diào)用新進(jìn)程時(shí),argv作為新進(jìn)程的main函數(shù)的參數(shù)。而envp可作為新進(jìn)程的環(huán)境變量,傳遞給新的進(jìn)程,從而變量它可用的環(huán)境變量。

承接上一個(gè)例子,如果想用exec系統(tǒng)函數(shù)來(lái)啟動(dòng)ps進(jìn)程,則這6個(gè)不同的函數(shù)的調(diào)用語(yǔ)句為:

注:arg0為程序的名字,所以在這個(gè)例子中全為ps。

char *const ps_envp[] = {"PATH=/bin:usr/bin", "TERM=console", 0}; 
char *const ps_argv[] = {"ps", "au", 0}; 
 
execl("/bin/ps", "ps", "au", 0); 
execlp("ps", "ps", "au", 0); 
execle("/bin/ps", "ps", "au", 0, ps_envp); 
 
execv("/bin/ps", ps_argv); 
execvp("ps", ps_argv); 
execve("/bin/ps", ps_argv, ps_envp); 

下面我給出一個(gè)完整的例子,源文件名為new_ps_exec.c,代碼如下:

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{ 
  printf("Running ps with execlp\n"); 
  execlp("ps", "ps", "au", (char*)0); 
  printf("ps Done"); 
  exit(0); 
} 

運(yùn)行結(jié)果如下:

細(xì)心的話,可以發(fā)現(xiàn),最后的ps Done并沒(méi)有輸出,這是偶然嗎?并不是,因?yàn)槲覀儾](méi)有再一次返回到程序new_ps_exec.exe上,因?yàn)檎{(diào)用execlp函數(shù)時(shí),new_ps_exec.exe進(jìn)程被替換為ps進(jìn)程,當(dāng)ps進(jìn)程結(jié)束后,整個(gè)程序就結(jié)束了,并沒(méi)有回到原來(lái)的new_ps_exec.exe進(jìn)程上,原本的進(jìn)程new_ps_exec.exe不會(huì)再執(zhí)行,所以語(yǔ)句printf("ps Done");根本沒(méi)有機(jī)會(huì)執(zhí)行。

注意,一般情況下,exec函數(shù)是不會(huì)返回的,除非發(fā)生錯(cuò)誤返回-1,由exec啟動(dòng)的新進(jìn)程繼承了原進(jìn)程的許多特性,在原進(jìn)程中已打開(kāi)的文件描述符在新進(jìn)程中仍將保持打開(kāi),但任何在原進(jìn)程中已打開(kāi)的目錄流都將在新進(jìn)程中被關(guān)閉。

三、復(fù)制進(jìn)程映像——fork函數(shù)

1、fork函數(shù)的應(yīng)用

exec調(diào)用用新的進(jìn)程替換當(dāng)前執(zhí)行的進(jìn)程,而我們也可以用fork來(lái)復(fù)制一個(gè)新的進(jìn)程,新的進(jìn)程幾乎與原進(jìn)程一模一樣,執(zhí)行的代碼也完全相同,但新進(jìn)程有自己的數(shù)據(jù)空間、環(huán)境和文件描述符。

fork函數(shù)的原型為:

#include <sys/type.h> 
#include <unistd.h> 
 
pid_t fork(); 

注:在父進(jìn)程中,fork返回的是新的子進(jìn)程的PID,子進(jìn)程中的fork返回的是0,我們可以通過(guò)這一點(diǎn)來(lái)判斷父進(jìn)程和子進(jìn)程,如果fork調(diào)用失敗,它返回-1.

繼承上面的例子,下面我給出一個(gè)調(diào)用ps的例子,源文件名為new_ps_fork.c,代碼如下:

#include <unistd.h> 
#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
int main() 
{ 
  pid_t pid = fork(); 
  switch(pid) 
  { 
  case -1: 
    perror("fork failed"); 
    exit(1); 
    break; 
  case 0: 
    //這是在子進(jìn)程中,調(diào)用execlp切換為ps進(jìn)程 
    printf("\n"); 
    execlp("ps", "ps", "au", 0); 
    break; 
  default: 
    //這是在父進(jìn)程中,輸出相關(guān)提示信息 
    printf("Parent, ps Done\n"); 
    break; 
  } 
  exit(0); 
} 

輸出結(jié)果為:

我們可以看到,之前在第二點(diǎn)中沒(méi)有出現(xiàn)的ps Done是打印出來(lái)了,但是順序卻有點(diǎn)不對(duì),這是因?yàn)椋高M(jìn)程先于子程序執(zhí)行,所以先輸出了Parent, ps Done,那有沒(méi)有辦法讓它在子進(jìn)程輸出完之后再輸出,當(dāng)然有,就是用wait和waitpid函數(shù)。注意,一般情況下,父進(jìn)程與子進(jìn)程的生命周期是沒(méi)有關(guān)系的,即便父進(jìn)程退出了,子進(jìn)程仍然可以正常運(yùn)行。

2、等待一個(gè)進(jìn)程

wait函數(shù)和waitpid函數(shù)的原型為:

#include <sys/types.h> 
#include <sys/wait.h> 
 
pid_t wait(int *stat_loc); 
pid_t waitpid(pid_t pid, int *stat_loc, int options); 

wait用于在父進(jìn)程中調(diào)用,讓父進(jìn)程暫停執(zhí)行等待子進(jìn)程的結(jié)束,返回子進(jìn)程的PID,如果stat_loc不是空指針,狀態(tài)信息將被寫入stat_loc指向的位置。

waitpid等待進(jìn)程id為pid的子進(jìn)程的結(jié)束(pid為-1,將返回任一子進(jìn)程的信息),stat_loc參數(shù)的作用與wait函數(shù)相同,options用于改變waitpid的行為,其中有一個(gè)很重要的選項(xiàng)WNOHANG,它的作用是防止waippid調(diào)用者的執(zhí)行掛起。如果子進(jìn)程沒(méi)有結(jié)束或意外終止,它返回0,否則返回子進(jìn)程的pid。

改變后的程序保存為源文件new_ps_fork2.c,代碼如下:

#include <unistd.h> 
#include <sys/types.h> 
#include <stdio.h> 
#include <stdlib.h> 
 
int main() 
{ 
  pid_t pid = fork(); 
  int stat = 0; 
  switch(pid) 
  { 
  case -1: 
    perror("fork failed"); 
    exit(1); 
    break; 
  case 0: 
    //這是在子進(jìn)程中,調(diào)用execlp切換為ps進(jìn)程 
    printf("\n"); 
    execlp("ps", "ps", "au", 0); 
    break; 
  default: 
    //這是在父進(jìn)程中,等待子進(jìn)程結(jié)束并輸出相關(guān)提示信息 
    pid = wait(&stat); 
    printf("Child has finished: PID = %d\n", pid); 
    //檢查子進(jìn)程的退出狀態(tài) 
    if(WIFEXITED(stat)) 
      printf("Child exited with code %d\n", WEXITSTATUS(stat)); 
    else 
      printf("Child terminated abnormally\n"); 
    printf("Parent, ps Done\n"); 
    break; 
  } 
  exit(0); 
} 

輸出為:

可以看到這次的輸出終于正常了,Parent的輸出也在子進(jìn)程的輸出之后。

總結(jié)——三種啟動(dòng)新進(jìn)程方法的比較

首先是最簡(jiǎn)單的system函數(shù),它需要啟動(dòng)新的shell并在新的shell是執(zhí)行子進(jìn)程,所以對(duì)環(huán)境的依賴較大,而且效率也不高。同時(shí)system函數(shù)要等待子進(jìn)程的返回才能執(zhí)行下面的語(yǔ)句。

exec系統(tǒng)函數(shù)是用新的進(jìn)程來(lái)替換原先的進(jìn)程,效率較高,但是它不會(huì)返回到原先的進(jìn)程,也就是說(shuō)在exec函數(shù)后面的所以代碼都不會(huì)被執(zhí)行,除非exec調(diào)用失敗。然而exec啟動(dòng)的新進(jìn)程繼承了原進(jìn)程的許多特性,在原進(jìn)程中已打開(kāi)的文件描述符在新進(jìn)程中仍將保持打開(kāi),但需要注意,任何在原進(jìn)程中已打開(kāi)的目錄流都將在新進(jìn)程中被關(guān)閉。

fork則是用當(dāng)前的進(jìn)程來(lái)復(fù)制出一個(gè)新的進(jìn)程,新進(jìn)程與原進(jìn)程一模一樣,執(zhí)行的代碼也完全相同,但新進(jìn)程有自己的數(shù)據(jù)空間、環(huán)境變量和文件描述符,我們通常根據(jù)fork函數(shù)的返回值來(lái)確定當(dāng)前的進(jìn)程是子進(jìn)程還是父進(jìn)程,即它并不像exec那樣并不返回,而是返回一個(gè)pid_t的值用于判斷,我們還可以繼續(xù)執(zhí)行fork后面的代碼。感覺(jué)用fork與exec系列函數(shù)就能創(chuàng)建很多需的進(jìn)程。

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

  • Shell全局變量、局部變量與特殊變量的具體使用

    Shell全局變量、局部變量與特殊變量的具體使用

    本文主要介紹了Shell全局變量、局部變量與特殊變量的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • shell腳本實(shí)現(xiàn)多進(jìn)程運(yùn)行的方法示例

    shell腳本實(shí)現(xiàn)多進(jìn)程運(yùn)行的方法示例

    這篇文章主要給大家分享了shell腳本實(shí)現(xiàn)多進(jìn)程運(yùn)行的方法示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-06-06
  • Linux中Git集中操作命令匯總

    Linux中Git集中操作命令匯總

    小編給大家匯總了在Linux中Git集中操作命令,值得大家參考一下。
    2017-11-11
  • Bash Shell中雙引號(hào)中的感嘆號(hào)問(wèn)題小結(jié)

    Bash Shell中雙引號(hào)中的感嘆號(hào)問(wèn)題小結(jié)

    當(dāng)你在雙引號(hào)中使用感嘆號(hào)時(shí),如果你在雙引號(hào)中直接使用感嘆號(hào),它可能會(huì)被解釋為歷史擴(kuò)展的一部分,這篇文章主要介紹了Bash Shell中雙引號(hào)中的感嘆號(hào)問(wèn)題小結(jié),需要的朋友可以參考下
    2024-03-03
  • shell中的for循環(huán)用法詳解

    shell中的for循環(huán)用法詳解

    這篇文章主要介紹了shell中的for循環(huán)用法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 使用shell腳本判斷文件后綴的方法實(shí)例

    使用shell腳本判斷文件后綴的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于如何使用shell腳本判斷文件后綴的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • linux中&和&&,|和||及分號(hào)(;)的用法

    linux中&和&&,|和||及分號(hào)(;)的用法

    本文主要介紹了linux中&和&&,|和||及分號(hào)(;)的用法,我們經(jīng)常會(huì)用到,但是很多人會(huì)混淆,下面就來(lái)介紹一下具體用法,鞏固的大家的記憶,感興趣的可以了解一下
    2023-06-06
  • shell腳本實(shí)現(xiàn)快速生成xml格式sitemap實(shí)例分享

    shell腳本實(shí)現(xiàn)快速生成xml格式sitemap實(shí)例分享

    這篇文章主要介紹了shell腳本實(shí)現(xiàn)快速生成xml格式sitemap實(shí)例分享,只是本文的腳本首先需要一個(gè)創(chuàng)建好的URL集合文件,也就是數(shù)據(jù)源才可以生成,需要的朋友可以參考下
    2014-12-12
  • linux鏈接編譯詳解

    linux鏈接編譯詳解

    通過(guò)自己編寫Makefile文件來(lái)實(shí)現(xiàn)多目標(biāo)文件的鏈接,其實(shí)就是將gcc 編譯命令寫入到Makefile文件,通過(guò)執(zhí)行make 指令來(lái)實(shí)現(xiàn)編譯。這樣我不需要每次都敲入gcc -指令。直接輸入make就OK了。
    2014-02-02
  • Shell腳本從文件中逐行讀取內(nèi)容的幾種方法實(shí)例

    Shell腳本從文件中逐行讀取內(nèi)容的幾種方法實(shí)例

    今天小編就為大家分享一篇關(guān)于Shell腳本從文件中逐行讀取內(nèi)容的幾種方法實(shí)例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03

最新評(píng)論