C語言-系統(tǒng)-進程的創(chuàng)建

使用 system

C標準庫中的system 函數(shù)提供了一種調(diào)用其他程序的簡單方法,利用system 函數(shù)調(diào)用程序結(jié)果與從shell中執(zhí)行這個程序基本相似;也就是說system 函數(shù)可以運行一個shell腳本的命令

//案例:
#incude <stdio.h>
int main()
{
    int return_value;
    return_value = system("ls -l"); // 調(diào)用失敗返回 -1;
    return return_value;
}

使用fork和exec族函數(shù)

  1. fork()函數(shù)
    頭文件:#include <unistd.h>
    函數(shù)的一般形式:
        pid_t fork(void);

返回值:成功返回0,表示子進程;大于零表示父進程;失敗返回 -1,并設(shè)置錯誤代碼。
錯誤代碼:

EAGAIN:當前的進程數(shù)已經(jīng)達到了系統(tǒng)規(guī)定的上限
ENOMEM:內(nèi)存不足
// 案例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    pid_t pid;
    pid = fork();
    if (0 == pid)
    {
       printf("This is the child process, its ID is %d.\n ", (int)getpid());
       printf("This is the child process, its parent process's ID is %d.\n", (int)getppid());
     }
     else if (0 < pid)
     {
        printf("This is the parent process, its ID is %d.\n", (int)getpid());
      }
      else
      {
        perror("fork error");
        exit(1); // 0表示EXIT_SUCCESS;1表示EXIT_FAILURE
      }
      return 0;
}
fork() 和 vfork() 的區(qū)別:
        使用fork調(diào)用會為子進程復(fù)制父進程所擁有的資源(進程環(huán)境、棧堆等),而vfork設(shè)計時要求子進程立即調(diào)用exec,而不修改任何內(nèi)存,vfork新建的子進程則是和父進程共享所有的資源,在子進程中對數(shù)據(jù)的修改也就是對父進程數(shù)據(jù)的修改,這一點一定要注意。
        使用fork系統(tǒng)調(diào)用產(chǎn)生父子進程,在默認情況下無需人為干預(yù),父子進程的執(zhí)行順序是由操作系統(tǒng)調(diào)度的,誰先執(zhí)行并不確定。而對于vfork所生成的父子進程,父進程是在子進程調(diào)用了_exit或者exec后才會繼續(xù)執(zhí)行,不調(diào)用這兩個函數(shù)父進程會等待(父進程由于沒有收到子進程表示已執(zhí)行的相關(guān)信號所以進行等待)。
        vfork的出現(xiàn)是為了解決當初fork浪費用戶空間內(nèi)存的問題,因為在fork后,很有可能去執(zhí)行exec函數(shù)重生,vfork設(shè)計思想就是取消fork造成堆棧的復(fù)制,使用vfork可以避免資源的浪費,但是也帶了資源共享所產(chǎn)生的問題。
        在[Linux](http://lib.csdn.net/base/linux)中,對fork進行了優(yōu)化,調(diào)用時采用寫時復(fù)制 (COW,copy on write)的方式,在系統(tǒng)調(diào)用fork生成子進程的時候,不馬上為子進程復(fù)制父進程的資源,而是在遇到“寫入”(對資源進行修改)操作時才復(fù)制資源。它使得一個普通的fork調(diào)用非常類似于vfork,但又避免了vfork的缺點,使得vfork變得沒有必要。
  1. exec() 函數(shù)
    fork函數(shù)是用于創(chuàng)建一個子進程,該子進程幾乎是父進程的副本,而有時我們希望子進程去執(zhí)行另外的程序,exec函數(shù)族就提供了一個在進程中啟動另一個程序執(zhí)行的方法。它可以根據(jù)指定的文件名或目錄名找到可執(zhí)行文件,并用它來取代原調(diào)用進程的數(shù)據(jù)段、代碼段和堆棧段,在執(zhí)行完之后,原調(diào)用進程的內(nèi)容除了進程號外,其他全部被新程序的內(nèi)容替換了
    包含:execl()、execlp()、execle()、execv()、execvp()、execvpe()六個函數(shù)。
    頭文件:#include <unistd.h>
    函數(shù)的一般形式:
    int execl(const char *path, const char *arg, ...);
    int execlp(const char *file, const char *arg, ...);
    int execle(const char *path, const char *arg,
    ..., char * const envp[]);
    int execv(const char *path, char *const argv[]);
    int execvp(const char *file, char *const argv[]);
    int execvpe(const char *file, char *const argv[],
    char *const envp[]);
    注意:
    1.p:表示當前執(zhí)行路徑,無p則表示絕對經(jīng);
    2.l:用一個字符串數(shù)組作為調(diào)用程序的參數(shù),這個參數(shù)必須以一個NULL指針作為結(jié)束標志;
    3.v:以C語言中的varqs形式接受的參數(shù)列表;參數(shù)傳遞為構(gòu)造指針數(shù)組方式
    4.e:表示指明了環(huán)境變量列表的參數(shù);
    返回值:成功無返回值,失敗返回 -1;
    錯誤代碼:
在使用exec函數(shù)族時,一定要加上錯誤判斷語句。因為exec很容易執(zhí)行失敗,其中最常見的原因
有:
      ENOENT:找不到文件或路徑
      EFAULT:數(shù)組argv和envp忘記用NULL結(jié)束
      EACCES:沒有對應(yīng)可執(zhí)行文件的運行權(quán)限
// 案例:
  char *const ps_argv[] ={"ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL};
  char *const ps_envp[] ={"PATH=/bin:/usr/bin", "TERM=console", NULL};
  execl("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
  execlp("ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL);
  execle("/bin/ps", "ps", "-o", "pid,ppid,pgrp,session,tpgid,comm", NULL, ps_envp);
  execv("/bin/ps", ps_argv);
  execvp("ps", ps_argv);
  execve("/bin/ps", ps_argv, ps_envp);

注意:exec函數(shù)族形參展開時的前兩個參數(shù),第一個參數(shù)是帶路徑的執(zhí)行碼(execlp、execvp函數(shù)第一個參數(shù)是無路徑的,系統(tǒng)會根據(jù)PATH自動查找然后合成帶路徑的執(zhí)行碼),第二個是不帶路徑的執(zhí)行碼,執(zhí)行碼可以是二進制執(zhí)行碼和Shell腳本。

// 案例:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int spawn(char* program, char** arg_list)
{
  pid_t pid;
  pid = fork();
  if (-1 == pid)
  {
    perror("fork error");
    exit(1);
  }
  else if (0 == pid)
  {
    execvp(program, arg_list);
    fprintf(stderr, "an error occurred in execvp\n");
    abort();
  }
  else
  {
    return pid;
  }
}
int main()
{
  char* arg_list[] = { "ls", "-l", "/", NULL}; // 參數(shù)列表必須以NULL指針結(jié)束
  spawn("ls", arg_list);
  printf("done with main program\n");
  return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Linux 進程管理與程序開發(fā) 進程是Linux事務(wù)管理的基本單元,所有的進程均擁有自己獨立的處理環(huán)境和系統(tǒng)資源,...
    JamesPeng閱讀 2,512評論 1 14
  • 一、進程的創(chuàng)建和調(diào)度 相關(guān)概念: 最基礎(chǔ)的計算機動作被稱為指令(instruction)。 程序(program)...
    穹藍奧義閱讀 4,720評論 0 6
  • ### main函數(shù)執(zhí)行之前做了什么?(iOS) & dyld 是Apple 的動態(tài)鏈接器;在 xnu 內(nèi)核為程...
    天使君閱讀 700評論 0 1
  • 2017.6.19 晴 最近和兒子一起看了一部動畫電影《螢火蟲之墓》,看完之后心情久久不能平靜。 故事...
    李一寬閱讀 382評論 0 7
  • 電熱壺的水燒開了, 你卻裝作不知道。 咕咕的響聲沖破了靜寂, 你嫌它太吵。 只想忘記眼前的瑣事, 打開臺燈靜坐在書...
    四夕白水閱讀 302評論 0 4