進(jìn)程相關(guān)fork()/exec()/wait()

fork()

fork()將父進(jìn)程復(fù)制一份子進(jìn)程, 在子進(jìn)程中從fork()調(diào)用處繼續(xù)執(zhí)行, 之后的代碼在父子進(jìn)程中各自執(zhí)行一遍. 最終父進(jìn)程的fork()返回子進(jìn)程的pid, 子進(jìn)程的fork()返回0表示創(chuàng)建成功. 所以看起來仿佛fork()返回兩個(gè)返回值, 其實(shí)是兩個(gè)進(jìn)程的fork()各自的返回值, 通過返回值不同區(qū)分父子進(jìn)程.
getpid()獲取當(dāng)前進(jìn)程pid, getppid()獲取父進(jìn)程pid.
getuid()獲取當(dāng)前進(jìn)程實(shí)際用戶, geteuid()獲取當(dāng)前進(jìn)程有效用戶. 如使用sudo命令時(shí)shell進(jìn)程有效用戶就變?yōu)閞oot, 但實(shí)際用戶還是username.

循環(huán)創(chuàng)建子進(jìn)程如下所示:

當(dāng)pid==0即在子進(jìn)程中時(shí)要跳出循環(huán), 避免創(chuàng)建"孫進(jìn)程". 使得只有主進(jìn)程有調(diào)用fork

父子進(jìn)程各自的代碼段是獨(dú)立的, 各自的全局變量也是獨(dú)立的, 但對(duì)于只讀操作可以共享同一塊物理內(nèi)存, 寫時(shí)再復(fù)制, 虛擬地址空間還是獨(dú)立的.
父子進(jìn)程誰先執(zhí)行并不一定.
gdb使用set follow-fork-mode child/parent來跟蹤父進(jìn)程或子進(jìn)程, 注意要在運(yùn)行到 fork()前設(shè)置.

exec()函數(shù)族

調(diào)用exec函數(shù)會(huì)將當(dāng)前進(jìn)程的.text,.data段完全替換為新程序的.text和.data段, 但是不創(chuàng)建新進(jìn)程, 所以進(jìn)程id不變.

頭文件<unistd.h>
extern char **environ;
原型:
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[]);
execl()/execlp()/execle()

execl("/bin/ls", "ls", "-l", "-a", NULL)直接傳入文件路徑, 不需要PATH環(huán)境變量, 第二個(gè)參數(shù)起是命令行參數(shù)argv[0], argv[1]..., 命令行參數(shù)也是一個(gè)字符串?dāng)?shù)組, 結(jié)尾的哨兵NULL要顯式的寫出來.
execlp("ls", "ls", "-l", "-a", NULL) 該函數(shù)需要配合PATH來搜索需要加載的程序. 其第一個(gè)參數(shù)ls指的是要從PATH中查找的程序; 第二個(gè)參數(shù)ls指的是argv[0], 表示要被調(diào)用的程序. 此處文件中不需要引入環(huán)境變量extern char** environ, 函數(shù)會(huì)自動(dòng)去查找. 其中environ是一個(gè)指針數(shù)組, 每一個(gè)指針指向一個(gè)char*字符串. execlp()通常用來調(diào)用系統(tǒng)程序如ls, date, cp, cat等命令.
先聲明char* const envp[] = {"AA=11", "BB=22", NULL}; 然后將envp傳入execle("/bin/ls", "ls", "-l", "-a", NULL, envp). 原進(jìn)程會(huì)將環(huán)境變量信息傳遞給新進(jìn)程, 可以利用execle函數(shù)傳遞自己需要的環(huán)境變量信息.

execv()/execvp()/execve()

先聲明char* argv[]={"ls", "-l", "-a", NULL};char* const envp[] = {"AA=11", "BB=22", NULL}; 然后execv("/bin/ls", argv)直接聲明一個(gè)命令行參數(shù)數(shù)組, 再傳進(jìn)去. 這里的v指代argv. 同理, execvp("ls", argv)需要借助PATH, execve("/bin/ls", argv, envp)需要傳入環(huán)境變量.

若想將ps -aux輸出到屏幕的內(nèi)容輸出到一個(gè)文件中, 可以使用dup2(fd, STDOUT_FILENO)將文件描述符表1號(hào)的STDOUT_FILENO指向?qū)?yīng)文件的fd, 然后再execlp("ps", "ps", "aux", NULL).
注:1. 上述exec系列函數(shù)底層都是通過execve()系統(tǒng)調(diào)用實(shí)現(xiàn), 2. exec函數(shù)族成功了不返回值, 失敗了才返回errno, 所以后面的close(fd)實(shí)際上是不執(zhí)行的, 不過依賴于隱式回收可以在進(jìn)程結(jié)束時(shí)自動(dòng)關(guān)閉文件, 所以不寫close(fd)不會(huì)出錯(cuò). 如果exec失敗也不需要if判斷, 直接perror接exit即可

孤兒進(jìn)程

若父進(jìn)程先于子進(jìn)程結(jié)束, 則子進(jìn)程成為孤兒進(jìn)程, 其被/sbin/init進(jìn)程領(lǐng)養(yǎng)(pid=1)或是/usr/sbin/init進(jìn)程, 然后被回收.

僵尸進(jìn)程

子進(jìn)程死亡后父進(jìn)程未處理, 則子進(jìn)程成為僵尸進(jìn)程, PCB仍存放在內(nèi)核中. 使用ps aux查看時(shí)發(fā)現(xiàn)進(jìn)程名變成[進(jìn)程名]<defunct>, 表示是一個(gè)僵尸進(jìn)程, 狀態(tài)為Z. 另外運(yùn)行中的進(jìn)程狀態(tài)是R, 后臺(tái)運(yùn)行的狀態(tài)是S.
僵尸進(jìn)程已經(jīng)死亡, 無法用kill殺死, 所以只能回收. 回收一個(gè)僵尸進(jìn)程可以調(diào)用wait()或者waitpid(), 也可以將其父進(jìn)程殺死后使其變?yōu)楣聝哼M(jìn)程, 由init領(lǐng)養(yǎng)后回收.

wait()

pid_t wait(int *status)傳出參數(shù)status(配合宏)表示僵尸進(jìn)程的成因, 返回值為僵尸進(jìn)程pid. wait()函數(shù)可以清除PCB殘留信息, 使父進(jìn)程阻塞等待子進(jìn)程完成. 一次wait()調(diào)用只能回收一個(gè)子進(jìn)程.

// 當(dāng)子進(jìn)程正常結(jié)束時(shí)(如return 13或者 exit(13)), 可以獲取到退出信息13
if (WIFEXITED(status))
{
    printf("child exit with %d", WEXITSTATUS(status));
}
// 當(dāng)程序異常退出時(shí)(接收到信號(hào)), 獲取中斷信號(hào)(如9, kill -9)
// 當(dāng)kill不加參數(shù)時(shí)信號(hào)默認(rèn)為15-SIGTERM, 另外段錯(cuò)誤是11, 可使用kill -l查看各種信號(hào)
if (WIFSIGNALED(status))
{
    printf("child killed by %d", WTERMSIG(status));
}
if (WIFSTOPPED(status)
{
    printf("child stopped by %d", WSTOPSIG(status));
}
if (WIFCONTINUED(status))
{
    printf("child continued");
}

waitpid()

pid_t waitpid(pid_t pid, int* status, in options);同wait, 但可以指定pid進(jìn)程清理, 也可以不阻塞(options參數(shù)使用WNOHANG輪詢模式), options為0則為阻塞.

fork的子進(jìn)程默認(rèn)跟父進(jìn)程是一個(gè)進(jìn)程組的, 所以如果父進(jìn)程調(diào)用waitpid()時(shí)第一個(gè)參數(shù)傳0和傳-1是一樣的. 父子進(jìn)程組ID默認(rèn)為父進(jìn)程的ID
如果第一個(gè)參數(shù)傳-xxxx就會(huì)把這一進(jìn)程組的子進(jìn)程都回收, 使用ps -ajx可以查看到進(jìn)程組ID, 等價(jià)于kill -9 -xxxx(進(jìn)程組ID).
當(dāng)?shù)谌齻€(gè)參數(shù)為0時(shí), waitpid(-1, NULL, 0)等價(jià)于wait(NULL), 回收任意子進(jìn)程. 第三個(gè)參數(shù)傳WNOHANG時(shí)(需使用輪詢結(jié)構(gòu)), 非阻塞回收, 如果子進(jìn)程正在運(yùn)行函數(shù)返回0, 如果成功清理返回子進(jìn)程ID, 如果失敗(無子進(jìn)程)返回-1.

進(jìn)程組/會(huì)話

getpgrp()獲取當(dāng)前進(jìn)程的進(jìn)程組ID, getpgid獲取指定進(jìn)程的進(jìn)程組ID(傳0就是自身的). setpgid使某一進(jìn)程自立門戶, 成為新進(jìn)程組的組長.

會(huì)話的SID是創(chuàng)建該會(huì)話的領(lǐng)頭進(jìn)程的PID, 一般就是shell. Session的意義在于多個(gè)進(jìn)程組(job)在一個(gè)終端中運(yùn)行檬某,其中的一個(gè)為前臺(tái) job,它直接接收該終端的輸入并把結(jié)果輸出到該終端螟蝙。其它的 job 則在后臺(tái)運(yùn)行恢恼。
如果我們?cè)?session 中執(zhí)行了 nohup 等類似的命令,當(dāng) session 消亡時(shí)胶逢,相關(guān)的進(jìn)程并不會(huì)隨著 session 結(jié)束厅瞎,原因是這些進(jìn)程不再受 SIGHUP 信號(hào)的影響.
nohup java -jar app.jar >log 2>&1 &
最后一個(gè)&表示把條命令放到后臺(tái)執(zhí)行, 2>&1一定要寫到>log后面,才表示標(biāo)準(zhǔn)錯(cuò)誤輸出和標(biāo)準(zhǔn)輸出都重定向到log中.
本來1----->屏幕 (1指向屏幕)
執(zhí)行>log后, 1----->log (1指向log)
執(zhí)行2>&1后初坠, 2----->1 (2指向1,而1指向log,因此2也指向了log)

守護(hù)進(jìn)程

創(chuàng)建守護(hù)進(jìn)程: 1. 創(chuàng)建子進(jìn)程, fork() 2. 子進(jìn)程創(chuàng)建新會(huì)話,丟棄終端, setsid() 3. 移動(dòng)工作目錄到根目錄, chdir() 4. 改變umask掩碼, umask(0002) 5. 重定向012文件描述符到/dev/null(會(huì)話不需要終端), dup2() 6. 將1-5封裝到一個(gè)函數(shù)中來調(diào)用, 之后開始執(zhí)行守護(hù)進(jìn)程任務(wù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末彭雾,一起剝皮案震驚了整個(gè)濱河市碟刺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌薯酝,老刑警劉巖半沽,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異吴菠,居然都是意外死亡者填,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門做葵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來占哟,“玉大人,你說我怎么就攤上這事酿矢≌ズ酰” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵瘫筐,是天一觀的道長蜜暑。 經(jīng)常有香客問我,道長策肝,這世上最難降的妖魔是什么肛捍? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任隐绵,我火速辦了婚禮,結(jié)果婚禮上拙毫,老公的妹妹穿的比我還像新娘氢橙。我一直安慰自己,他們只是感情好恬偷,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布悍手。 她就那樣靜靜地躺著,像睡著了一般袍患。 火紅的嫁衣襯著肌膚如雪坦康。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天诡延,我揣著相機(jī)與錄音滞欠,去河邊找鬼。 笑死肆良,一個(gè)胖子當(dāng)著我的面吹牛筛璧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惹恃,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼夭谤,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了巫糙?” 一聲冷哼從身側(cè)響起朗儒,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎参淹,沒想到半個(gè)月后醉锄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡浙值,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年恳不,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片开呐。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡烟勋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出负蚊,到底是詐尸還是另有隱情神妹,我是刑警寧澤,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布家妆,位于F島的核電站鸵荠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏伤极。R本人自食惡果不足惜蛹找,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一姨伤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧庸疾,春花似錦乍楚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至金顿,卻和暖如春臊泌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背揍拆。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來泰國打工渠概, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嫂拴。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓播揪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親筒狠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子猪狈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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

  • 引出 我們學(xué)習(xí)了進(jìn)程,是為了去用多進(jìn)程窟蓝,那么罪裹,為什么需要用到多進(jìn)程呢? 1:為了提高效率运挫,支持大用戶量的并發(fā)。 2...
    小鼻子球球小昏昏閱讀 288評(píng)論 0 0
  • Linux 進(jìn)程管理與程序開發(fā) 進(jìn)程是Linux事務(wù)管理的基本單元套耕,所有的進(jìn)程均擁有自己獨(dú)立的處理環(huán)境和系統(tǒng)資源谁帕,...
    JamesPeng閱讀 2,471評(píng)論 1 14
  • 使用 system C標(biāo)準(zhǔn)庫中的system 函數(shù)提供了一種調(diào)用其他程序的簡(jiǎn)單方法,利用system 函數(shù)調(diào)用程序...
    一葉之界閱讀 2,165評(píng)論 0 0
  • ### main函數(shù)執(zhí)行之前做了什么?(iOS) & dyld 是Apple 的動(dòng)態(tài)鏈接器冯袍;在 xnu 內(nèi)核為程...
    天使君閱讀 692評(píng)論 0 1
  • 基本概念 進(jìn)程是一個(gè)可執(zhí)行程序的實(shí)例匈挖,程序代碼依托一個(gè)進(jìn)程運(yùn)行;進(jìn)程由用戶空間和一系列內(nèi)核數(shù)據(jù)結(jié)構(gòu)構(gòu)成康愤。內(nèi)核數(shù)據(jù)段...
    loopppp閱讀 495評(píng)論 0 0