多進(jìn)程(一)

本文轉(zhuǎn)載自實(shí)驗(yàn)樓:多進(jìn)程(一)

概述

進(jìn)程的概念這里就不再過多的贅述了,市面上幾乎關(guān)于計(jì)算機(jī)操作系統(tǒng)的書都有詳細(xì)的描述耀销。 在基本的概念里我們學(xué)習(xí)一下Linux進(jìn)程狀態(tài)

R (TASK_RUNNING),可執(zhí)行狀態(tài)氯庆。
只有在該狀態(tài)的進(jìn)程才可能在CPU上運(yùn)行腻惠。而同一時(shí)刻可能有多個(gè)進(jìn)程處于可執(zhí)行狀態(tài),這些進(jìn)程的task_struct結(jié)構(gòu)(進(jìn)程控制塊)被放入對(duì)應(yīng)CPU的可執(zhí)行隊(duì)列中(一個(gè)進(jìn)程最多只能出現(xiàn)在一個(gè)CPU的可執(zhí)行隊(duì)列中)勿璃。進(jìn)程調(diào)度器的任務(wù)就是從各個(gè)CPU的可執(zhí)行隊(duì)列中分別選擇一個(gè)進(jìn)程在該CPU上運(yùn)行。
很多操作系統(tǒng)教科書將正在CPU上執(zhí)行的進(jìn)程定義為RUNNING狀態(tài)推汽、而將可執(zhí)行但是尚未被調(diào)度執(zhí)行的進(jìn)程定義為READY狀態(tài)补疑,這兩種狀態(tài)在linux下統(tǒng)一為 TASK_RUNNING狀態(tài)。

S (TASK_INTERRUPTIBLE)歹撒,可中斷的睡眠狀態(tài)莲组。
處于這個(gè)狀態(tài)的進(jìn)程因?yàn)榈却衬呈录陌l(fā)生(比如等待socket連接、等待信號(hào)量)暖夭,而被掛起锹杈。這些進(jìn)程的task_struct結(jié)構(gòu)被放入對(duì)應(yīng)事件的等待隊(duì)列中撵孤。當(dāng)這些事件發(fā)生時(shí)(由外部中斷觸發(fā)、或由其他進(jìn)程觸發(fā))竭望,對(duì)應(yīng)的等待隊(duì)列中的一個(gè)或多個(gè)進(jìn)程將被喚醒邪码。
通過ps命令我們會(huì)看到,一般情況下咬清,進(jìn)程列表中的絕大多數(shù)進(jìn)程都處于TASK_INTERRUPTIBLE狀態(tài)(除非機(jī)器的負(fù)載很高)闭专。畢竟CPU就這么一兩個(gè),進(jìn)程動(dòng)輒幾十上百個(gè)枫振,如果不是絕大多數(shù)進(jìn)程都在睡眠喻圃,CPU又怎么響應(yīng)得過來萤彩。

D (TASK_UNINTERRUPTIBLE)粪滤,不可中斷的睡眠狀態(tài)。
與TASK_INTERRUPTIBLE狀態(tài)類似雀扶,進(jìn)程處于睡眠狀態(tài)杖小,但是此刻進(jìn)程是不可中斷的。不可中斷愚墓,指的并不是CPU不響應(yīng)外部硬件的中斷予权,而是指進(jìn)程不響應(yīng)異步信號(hào)。 絕大多數(shù)情況下浪册,進(jìn)程處在睡眠狀態(tài)時(shí)扫腺,總是應(yīng)該能夠響應(yīng)異步信號(hào)的。否則你將驚奇的發(fā)現(xiàn)村象,kill -9竟然殺不死一個(gè)正在睡眠的進(jìn)程了笆环!于是我們也很好理解,為什么ps命令看到的進(jìn)程幾乎不會(huì)出現(xiàn)TASK_UNINTERRUPTIBLE狀態(tài)厚者,而總是TASK_INTERRUPTIBLE狀態(tài)躁劣。
而TASK_UNINTERRUPTIBLE狀態(tài)存在的意義就在于,內(nèi)核的某些處理流程是不能被打斷的库菲。如果響應(yīng)異步信號(hào)账忘,程序的執(zhí)行流程中就會(huì)被插入一段用于處理異步信號(hào)的流程(這個(gè)插入的流程可能只存在于內(nèi)核態(tài),也可能延伸到用戶態(tài))熙宇,于是原有的流程就被中斷了鳖擒。(參見《linux內(nèi)核異步中斷淺析》) 在進(jìn)程對(duì)某些硬件進(jìn)行操作時(shí)(比如進(jìn)程調(diào)用read系統(tǒng)調(diào)用對(duì)某個(gè)設(shè)備文件進(jìn)行讀操作闷营,而read系統(tǒng)調(diào)用最終執(zhí)行到對(duì)應(yīng)設(shè)備驅(qū)動(dòng)的代碼照捡,并與對(duì)應(yīng)的物理設(shè)備進(jìn)行交互),可能需要使用TASK_UNINTERRUPTIBLE狀態(tài)對(duì)進(jìn)程進(jìn)行保護(hù)盗飒,以避免進(jìn)程與設(shè)備交互的過程被打斷烈拒,造成設(shè)備陷入不可控的狀態(tài)圆裕。這種情況下的TASK_UNINTERRUPTIBLE狀態(tài)總是非常短暫的广鳍,通過ps命令基本上不可能捕捉到。
linux系統(tǒng)中也存在容易捕捉的TASK_UNINTERRUPTIBLE狀態(tài)吓妆。執(zhí)行vfork系統(tǒng)調(diào)用后赊时,父進(jìn)程將進(jìn)入TASK_UNINTERRUPTIBLE狀態(tài),直到子進(jìn)程調(diào)用exit或exec(參見《神奇的vfork》)行拢。 通過下面的代碼就能得到處于TASK_UNINTERRUPTIBLE狀態(tài)的進(jìn)程:

$ ps -ax | grep a\.out
4371 pts/0 D+ 0:00 ./a.out
4372 pts/0 S+ 0:00 ./a.out
4374 pts/1 S+ 0:00 grep a.out

然后我們可以試驗(yàn)一下TASK_UNINTERRUPTIBLE狀態(tài)的威力祖秒。不管kill還是kill -9,這個(gè)TASK_UNINTERRUPTIBLE狀態(tài)的父進(jìn)程依然屹立不倒舟奠。

T (TASK_STOPPED or TASK_TRACED)竭缝,暫停狀態(tài)或跟蹤狀態(tài)。
向進(jìn)程發(fā)送一個(gè)SIGSTOP信號(hào)沼瘫,它就會(huì)因響應(yīng)該信號(hào)而進(jìn)入TASK_STOPPED狀態(tài)(除非該進(jìn)程本身處于TASK_UNINTERRUPTIBLE狀態(tài)而不響應(yīng)信號(hào))抬纸。(SIGSTOP與SIGKILL信號(hào)一樣,是非常強(qiáng)制的耿戚。不允許用戶進(jìn)程通過signal系列的系統(tǒng)調(diào)用重新設(shè)置對(duì)應(yīng)的信號(hào)處理函數(shù)湿故。) 向進(jìn)程發(fā)送一個(gè)SIGCONT信號(hào),可以讓其從TASK_STOPPED狀態(tài)恢復(fù)到TASK_RUNNING狀態(tài)膜蛔。
當(dāng)進(jìn)程正在被跟蹤時(shí)坛猪,它處于TASK_TRACED這個(gè)特殊的狀態(tài)≡砉桑“正在被跟蹤”指的是進(jìn)程暫停下來墅茉,等待跟蹤它的進(jìn)程對(duì)它進(jìn)行操作。比如在gdb中對(duì)被跟蹤的進(jìn)程下一個(gè)斷點(diǎn)呜呐,進(jìn)程在斷點(diǎn)處停下來的時(shí)候就處于TASK_TRACED狀態(tài)就斤。而在其他時(shí)候,被跟蹤的進(jìn)程還是處于前面提到的那些狀態(tài)卵史。
對(duì)于進(jìn)程本身來說战转,TASK_STOPPED和TASK_TRACED狀態(tài)很類似,都是表示進(jìn)程暫停下來以躯。 而TASK_TRACED狀態(tài)相當(dāng)于在TASK_STOPPED之上多了一層保護(hù)槐秧,處于TASK_TRACED狀態(tài)的進(jìn)程不能響應(yīng)SIGCONT信號(hào)而被喚醒。只能等到調(diào)試進(jìn)程通過ptrace系統(tǒng)調(diào)用執(zhí)行PTRACE_CONT忧设、PTRACE_DETACH等操作(通過ptrace系統(tǒng)調(diào)用的參數(shù)指定操作)刁标,或調(diào)試進(jìn)程退出,被調(diào)試的進(jìn)程才能恢復(fù)TASK_RUNNING狀態(tài)址晕。

Z (TASK_DEAD – EXIT_ZOMBIE)膀懈,退出狀態(tài),進(jìn)程成為僵尸進(jìn)程谨垃。
進(jìn)程在退出的過程中启搂,處于TASK_DEAD狀態(tài)硼控。
在這個(gè)退出過程中,進(jìn)程占有的所有資源將被回收胳赌,除了task_struct結(jié)構(gòu)(以及少數(shù)資源)以外牢撼。于是進(jìn)程就只剩下task_struct這么個(gè)空殼,故稱為僵尸疑苫。 之所以保留task_struct熏版,是因?yàn)閠ask_struct里面保存了進(jìn)程的退出碼、以及一些統(tǒng)計(jì)信息捍掺。而其父進(jìn)程很可能會(huì)關(guān)心這些信息撼短。比如在shell中,$?變量就保存了最后一個(gè)退出的前臺(tái)進(jìn)程的退出碼挺勿,而這個(gè)退出碼往往被作為if語(yǔ)句的判斷條件曲横。 當(dāng)然,內(nèi)核也可以將這些信息保存在別的地方满钟,而將task_struct結(jié)構(gòu)釋放掉胜榔,以節(jié)省一些空間胳喷。但是使用task_struct結(jié)構(gòu)更為方便湃番,因?yàn)樵趦?nèi)核中已經(jīng)建立了從pid到task_struct查找關(guān)系,還有進(jìn)程間的父子關(guān)系吭露。釋放掉task_struct吠撮,則需要建立一些新的數(shù)據(jù)結(jié)構(gòu),以便讓父進(jìn)程找到它的子進(jìn)程的退出信息讲竿。
父進(jìn)程可以通過wait系列的系統(tǒng)調(diào)用(如wait4泥兰、waitid)來等待某個(gè)或某些子進(jìn)程的退出,并獲取它的退出信息题禀。然后wait系列的系統(tǒng)調(diào)用會(huì)順便將子進(jìn)程的尸體(task_struct)也釋放掉鞋诗。 子進(jìn)程在退出的過程中,內(nèi)核會(huì)給其父進(jìn)程發(fā)送一個(gè)信號(hào)迈嘹,通知父進(jìn)程來“收尸”削彬。這個(gè)信號(hào)默認(rèn)是SIGCHLD,但是在通過clone系統(tǒng)調(diào)用創(chuàng)建子進(jìn)程時(shí)秀仲,可以設(shè)置這個(gè)信號(hào)融痛。
$ ps -ax | grep a.out10410 pts/0 S+ 0:00 ./a.out10411 pts/0 Z+ 0:00 [a.out]0413 pts/1 S+ 0:00 grep a.out

只要父進(jìn)程不退出,這個(gè)僵尸狀態(tài)的子進(jìn)程就一直存在神僵。那么如果父進(jìn)程退出了呢雁刷,誰(shuí)又來給子進(jìn)程“收尸”? 當(dāng)進(jìn)程退出的時(shí)候保礼,會(huì)將它的所有子進(jìn)程都托管給別的進(jìn)程(使之成為別的進(jìn)程的子進(jìn)程)沛励。托管給誰(shuí)呢责语?可能是退出進(jìn)程所在進(jìn)程組的下一個(gè)進(jìn)程(如果存在的話),或者是1號(hào)進(jìn)程目派。所以每個(gè)進(jìn)程鹦筹、每時(shí)每刻都有父進(jìn)程存在。除非它是1號(hào)進(jìn)程址貌。
1號(hào)進(jìn)程铐拐,pid為1的進(jìn)程,又稱init進(jìn)程练对。 linux系統(tǒng)啟動(dòng)后遍蟋,第一個(gè)被創(chuàng)建的用戶態(tài)進(jìn)程就是init進(jìn)程。它有兩項(xiàng)使命: 1螟凭、執(zhí)行系統(tǒng)初始化腳本虚青,創(chuàng)建一系列的進(jìn)程(它們都是init進(jìn)程的子孫); 2螺男、在一個(gè)死循環(huán)中等待其子進(jìn)程的退出事件棒厘,并調(diào)用waitid系統(tǒng)調(diào)用來完成“收尸”工作; init進(jìn)程不會(huì)被暫停下隧、也不會(huì)被殺死(這是由內(nèi)核來保證的)奢人。它在等待子進(jìn)程退出的過程中處于TASK_INTERRUPTIBLE狀態(tài),“收尸”過程中則處于TASK_RUNNING狀態(tài)淆院。

X (TASK_DEAD – EXIT_DEAD)何乎,退出狀態(tài),進(jìn)程即將被銷毀土辩。
而進(jìn)程在退出過程中也可能不會(huì)保留它的task_struct支救。比如這個(gè)進(jìn)程是多線程程序中被detach過的進(jìn)程(進(jìn)程?線程拷淘?參見《linux線程淺析》)各墨。或者父進(jìn)程通過設(shè)置SIGCHLD信號(hào)的handler為SIG_IGN启涯,顯式的忽略了SIGCHLD信號(hào)贬堵。(這是posix的規(guī)定,盡管子進(jìn)程的退出信號(hào)可以被設(shè)置為SIGCHLD以外的其他信號(hào)逝嚎。) 此時(shí)扁瓢,進(jìn)程將被置于EXIT_DEAD退出狀態(tài),這意味著接下來的代碼立即就會(huì)將該進(jìn)程徹底釋放补君。所以EXIT_DEAD狀態(tài)是非常短暫的引几,幾乎不可能通過ps命令捕捉到。

以上內(nèi)容均摘自博文:http://blog.csdn.net/huzia/article/details/18946491

進(jìn)程標(biāo)識(shí)
獲取進(jìn)程標(biāo)志號(hào)(pid)的API,主要有兩個(gè)函數(shù):getpidgetppid
需要包含的頭文件:

  • <sys/types.h>
  • <unistd.h>

函數(shù)原型:pid_t getpid(void) 功能:獲取當(dāng)前進(jìn)程ID 返回值:調(diào)用進(jìn)程的進(jìn)程ID
函數(shù)原型:pid_t getppid(void) 功能:獲取父進(jìn)程ID 返回值:調(diào)用進(jìn)程的父進(jìn)程ID

Linux 下 C 進(jìn)程內(nèi)存布局

1.C 進(jìn)程內(nèi)存布局說明
text:代碼段伟桅。存放的是程序的全部代碼(指令)敞掘,來源于二進(jìn)制可執(zhí)行文件中的代碼部分
initialized data(簡(jiǎn)稱data段)和uninitialized data(簡(jiǎn)稱bss段)組成了數(shù)據(jù)段。
其中data段存放的是已初始化全局變量和已初始化static局部變量楣铁,來源于二進(jìn)制可執(zhí)行文件中的數(shù)據(jù)部分玖雁;bss段存放的是未初始化全局變量和未初始化static局部變量,其內(nèi)容不來源于二進(jìn)制可執(zhí)行文件中的數(shù)據(jù)部分(也就是說:二進(jìn)制可執(zhí)行文件中的數(shù)據(jù)部分沒有未初始化全局變量和未初始化static局部變量)盖腕。根據(jù)C語(yǔ)言標(biāo)準(zhǔn)規(guī)定赫冬,他們的初始值必須為0,因此bss段存放的是全0溃列。將bss段清0的工作是由系統(tǒng)在加載二進(jìn)制文件后劲厌,開始執(zhí)行程序前完成的,系統(tǒng)執(zhí)行這個(gè)清0操作是由內(nèi)核的一段代碼完成的听隐,這段代碼就是即將介紹的exec系統(tǒng)調(diào)用补鼻。至于exec從內(nèi)存什么地方開始清0以及要清0多少空間,則是由記錄在二進(jìn)制可執(zhí)行文件中的信息決定的(即:二進(jìn)制文件中記錄了text雅任、data风范、bss段的大小)
malloc是從heap(堆)中分配空間的沪么。
stack(棧)存放的是動(dòng)態(tài)局部變量硼婿。
當(dāng)子函數(shù)被調(diào)用時(shí),系統(tǒng)會(huì)從棧中分配空間給該子函數(shù)的動(dòng)態(tài)局部變量(注意:此時(shí)棧向內(nèi)存低地址延伸)成玫;當(dāng)子函數(shù)返回時(shí)加酵,系統(tǒng)的棧會(huì)向內(nèi)存高地址延伸拳喻,這相當(dāng)于釋放子函數(shù)的動(dòng)態(tài)局部變量的內(nèi)存空間哭当。我們假設(shè)一下,main函數(shù)在調(diào)用子函數(shù)A后立即調(diào)用子函數(shù)B冗澈,那么子函數(shù)B的動(dòng)態(tài)局部變量會(huì)覆蓋原來子函數(shù)A的動(dòng)態(tài)局部變量的存儲(chǔ)空間钦勘,這就是子函數(shù)不能互相訪問對(duì)方動(dòng)態(tài)局部變量的根本物理原因。

內(nèi)存的最高端存放的是命令行參數(shù)和環(huán)境變量亚亲,將命令行參數(shù)和環(huán)境變量放到指定位置這個(gè)操作是由OS的一段代碼(exec系統(tǒng)調(diào)用)在加載二進(jìn)制文件到內(nèi)存后彻采,開始運(yùn)行程序前完成的。
Linux下C進(jìn)程內(nèi)存布局可以由下面的程序的運(yùn)行結(jié)果來獲得驗(yàn)證:

//memery.c
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3
 4 int global_init_val = 100;
 5 int global_noninit_val;
 6 extern char **environ;
 7
 8 int main(int argc, char *argv[], char *envp[])
 9 {
10         static int localstaticval = 10;
11         char *localval;
12         localval = malloc(10);
13         printf("address of text  is : %p\n", main);
14         printf("address of data  is : %p, %p\n", &global_init_val, &localstaticval);
15         printf("address of bss   is : %p\n", &global_noninit_val);
16         printf("address of heap  is : %p\n", localval);
17         printf("address of stack is : %p\n", &localval);
18         free(localval);
19
20         printf("&environ = %p, environ = %p\n", &envp, envp);
21         printf("&argv = %p, argv = %p\n", &argv, argv);
22         return 0;
23  }

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

1 address of text  is : 0x8048454
2 address of data  is : 0x804a01c, 0x804a020
3 address of bss   is : 0x804a02c
4 address of heap  is : 0x96e1008
5 address of stack is : 0xbffca8bc
6 &environ = 0xbffca8d8, environ = 0xbffca97c
7 &argv = 0xbffca8d4, argv = 0xbffca974

運(yùn)行結(jié)果分析: 運(yùn)行結(jié)果的第1(2肛响、3、4惜索、5特笋、6、7)行是由程序的第13(14巾兆、15猎物、16虎囚、17、20蔫磨、21)行打印的淘讥。 由運(yùn)行結(jié)果的第1、2堤如、3蒲列、4行可知,存放的是程序代碼的text段位于進(jìn)程地址空間的最低端搀罢;往上是存放已初始化全局變量和已初始化static局部變量的data段嫉嘀;往上是存放未初始化全局變量的bss段;往上是堆區(qū)(heap)魄揉。 由運(yùn)行結(jié)果的第7剪侮、6、5行可知洛退,命令行參數(shù)和環(huán)境變量存放在進(jìn)程地址空間的最高端瓣俯;往下是存放動(dòng)態(tài)局部變量的棧區(qū)(stack)。

  1. 環(huán)境變量的獲取與設(shè)置
    壞境變量在內(nèi)存中通常是一字符串環(huán)境變量名=環(huán)境變量值的形式存放兵怯。對(duì)壞境變量含義的急事依賴于具體的應(yīng)用程序彩匕。我們的程序可能會(huì)調(diào)用Linux系統(tǒng)的環(huán)境變量,甚至修改環(huán)境變量媒区,所以驼仪,Linux向我們提供了這種API。
    需要包含的頭文件:<stdlib.h>

函數(shù)原型: char * getenc(const char * name) 返回字符指針袜漩,該指針指向變量名為name的環(huán)境變量的值字符串绪爸。
int putenv(const char * str) 將“環(huán)境變量=環(huán)境變量值”形式的字符創(chuàng)增加到環(huán)境變量列表中;如果該環(huán)境變量已存在宙攻,則更新已有的值奠货。
int setenv(const char * name, const char * value, int rewrite) 設(shè)置名字為name的環(huán)境變量的值為value;如果該環(huán)境變量已存在座掘,且rewrite不為0递惋,用新值替換舊值;rewrite為0溢陪,就不做任何事萍虽。

//env.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[], char *envp[])
{
        char **ptr;
        for (ptr = envp; *ptr != 0; ptr++)   /* and all env strings */
                printf ("%s\n", *ptr);

        printf ("\n\n--------My environment variable-------\n\n");
        printf ("USERNAME is %s\n", getenv("USERNAME"));
        putenv ("USERNAME=shiyanlou");

        printf ("USERNAME is %s\n", getenv("USERNAME"));
        setenv ("USERNAME", "shiyanlou-2", 0);

        printf ("USERNAME is %s\n", getenv("USERNAME"));
        setenv ("USERNAME", "shiyanlou-2", 1);

        printf ("USERNAME is %s\n", getenv("USERNAME"));

        return 0;
}

進(jìn)程控制 -- fork

1.fork 的機(jī)制與特性

父進(jìn)程調(diào)用fork將會(huì)產(chǎn)生一個(gè)子進(jìn)程。此時(shí)會(huì)有2個(gè)問題:
子進(jìn)程的代碼從哪里來形真?
子進(jìn)程首次被OS調(diào)度時(shí)杉编,執(zhí)行的第1條代碼是哪條代碼?

子進(jìn)程的代碼是父進(jìn)程代碼的一個(gè)完全相同拷貝。事實(shí)上不僅僅是text段王财,子進(jìn)程的全部進(jìn)程空間(包括:text/data/bss/heap/stack/command line/environment variables)都是父進(jìn)程空間的一個(gè)完全拷貝卵迂。 下一個(gè)問題是:誰(shuí)為子進(jìn)程分配了內(nèi)存空間?誰(shuí)拷貝了父進(jìn)程空間的內(nèi)容到子進(jìn)程的內(nèi)存空間绒净?fork當(dāng)仁不讓见咒!事實(shí)上,查看fork實(shí)現(xiàn)的源代碼挂疆,由4部分工作組成:首先改览,為子進(jìn)程分配內(nèi)存空間;然后缤言,將父進(jìn)程空間的全部?jī)?nèi)容拷貝到分配給子進(jìn)程的內(nèi)存空間宝当;然后在內(nèi)核數(shù)據(jù)結(jié)構(gòu)中創(chuàng)建并正確初始化子進(jìn)程的PCB(包括2個(gè)重要信息:子進(jìn)程pid,PC的值=善后代碼的第1條指令地址)胆萧;最后是一段善后代碼庆揩。 由于子進(jìn)程的PCB已經(jīng)產(chǎn)生,所以子進(jìn)程已經(jīng)出生跌穗,因此子進(jìn)程就可以被OS調(diào)度到來運(yùn)行订晌。子進(jìn)程首次被OS調(diào)度時(shí),執(zhí)行的第1條代碼在fork內(nèi)部蚌吸,不過從應(yīng)用程序的角度來看锈拨,子進(jìn)程首次被OS調(diào)度時(shí),執(zhí)行的第1條代碼是從fork返回羹唠。這就導(dǎo)致了fork被調(diào)用1次奕枢,卻返回2次:父、子進(jìn)程中各返回1次佩微。對(duì)于應(yīng)用程序員而言缝彬,最重要的是fork的2次返回值不一樣,父進(jìn)程返回值是子進(jìn)程的pid喊衫,子進(jìn)程的返回值是0跌造。 至于子進(jìn)程產(chǎn)生后,父族购、子進(jìn)程誰(shuí)先運(yùn)行,取決于OS調(diào)度策略陵珍,應(yīng)用程序員無法控制寝杖。 以上分析了fork的內(nèi)部實(shí)現(xiàn)以及對(duì)應(yīng)用程序的影響。如果應(yīng)用程序員覺得難以理解的話互纯,可以暫時(shí)拋開瑟幕,只要記住3個(gè)結(jié)論即可:
fork函數(shù)被調(diào)用1次(在父進(jìn)程中被調(diào)用),但返回2次(父、子進(jìn)程中各返回一次)只盹。兩次返回的區(qū)別是子進(jìn)程的返回值是0辣往,而父進(jìn)程的返回值則是子進(jìn)程的進(jìn)程ID。
父殖卑、子進(jìn)程完全一樣(代碼站削、數(shù)據(jù)),子進(jìn)程從fork內(nèi)部開始執(zhí)行孵稽;父许起、子進(jìn)程從fork返回后,接著執(zhí)行下一條語(yǔ)句菩鲜。
一般來說园细,在fork之后是父進(jìn)程先執(zhí)行還是子進(jìn)程先執(zhí)行是不確定的,應(yīng)用程序員無法控制接校。

2.fork 實(shí)例分析

//fork.c
 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5
 6 #define err_sys(info)    \     
 7    {                      \   
 8         printf ("%s\n", info);\  
 9         exit(0); \               
10    }
11
12 int glob = 6;  /* external variable in initialized data */
13 char buf[ ] = "a write to stdout\n";
14 
15 int main(void)
16 {
17     int var;  /* automatic variable on the stack */
18     pid_t pid;
19     var = 88;
20 
21     if ((write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1))
22         err_sys("write error");
23 
24     printf("before fork\n");  /* we don't flush stdout */
25 
26     if ( (pid = fork()) < 0) {
27         err_sys("fork error");
28     } else if (pid == 0) {   /* child */
29        glob++;      /* modify variables */
30        var++;
31     } else {
32         sleep(2);   /* parent */
33     }
34
35     printf("pid = %d, ppid = %d, glob = %d, var = %d\n", getpid(),getppid(), glob, var);
36     exit(0);
37 }

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

1 a write to stdout
2 before fork
3 pid = 9009, ppid = 9008, glob = 7, var = 89
4 pid = 9008, ppid = 8979, glob = 6, var = 88

運(yùn)行結(jié)果分析: 結(jié)果的第1行是由父進(jìn)程的21行打用推怠; 結(jié)果的第2行是由父進(jìn)程的24行打又朊恪伦乔; 由于父進(jìn)程在24行睡眠了2秒,因此fork返回后董习,子進(jìn)程先于父進(jìn)程運(yùn)行是大概率事件烈和,所以子進(jìn)程運(yùn)行到25行打印出結(jié)果中的第3行。由于子進(jìn)程會(huì)拷貝父進(jìn)程的整個(gè)進(jìn)程空間(這其中包括數(shù)據(jù))皿淋,因此當(dāng)子進(jìn)程26行從fork返回后招刹,子進(jìn)程中的glob=6,var=88(拷貝自父進(jìn)程的數(shù)據(jù))窝趣。此時(shí)子進(jìn)程中pid=0疯暑,因此子進(jìn)程會(huì)執(zhí)行29、30行哑舒,當(dāng)子進(jìn)程到達(dá)35行時(shí)妇拯,將打印glob=7,var=89洗鸵。

雖然越锈,子進(jìn)程改變了glob和var的值,但它僅僅是改變了子進(jìn)程中的glob和var膘滨,而影響不了父進(jìn)程中的glob和var甘凭。在子進(jìn)程出生后,父火邓、子進(jìn)程的進(jìn)程空間(代碼丹弱、數(shù)據(jù)等)就是獨(dú)立德撬,互不干擾的。因此當(dāng)父進(jìn)程運(yùn)行到35行躲胳,將會(huì)打印父進(jìn)程中的glob和var的值蜓洪,他們分別是6和88,這就是運(yùn)行結(jié)果的第4行坯苹。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隆檀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子北滥,更是在濱河造成了極大的恐慌刚操,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件再芋,死亡現(xiàn)場(chǎng)離奇詭異菊霜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)济赎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門鉴逞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人司训,你說我怎么就攤上這事构捡。” “怎么了壳猜?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵勾徽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我统扳,道長(zhǎng)喘帚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任咒钟,我火速辦了婚禮吹由,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朱嘴。我一直安慰自己倾鲫,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布萍嬉。 她就那樣靜靜地躺著乌昔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪帚湘。 梳的紋絲不亂的頭發(fā)上玫荣,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音大诸,去河邊找鬼捅厂。 笑死,一個(gè)胖子當(dāng)著我的面吹牛资柔,可吹牛的內(nèi)容都是我干的焙贷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼贿堰,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼辙芍!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起羹与,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤故硅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后纵搁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吃衅,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年腾誉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了徘层。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡利职,死狀恐怖趣效,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猪贪,我是刑警寧澤跷敬,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站热押,受9級(jí)特大地震影響西傀,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜楞黄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一池凄、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧鬼廓,春花似錦肿仑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至雷蹂,卻和暖如春伟端,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背匪煌。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工责蝠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留党巾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓霜医,卻偏偏與公主長(zhǎng)得像齿拂,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子肴敛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

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

  • 又來到了一個(gè)老生常談的問題署海,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個(gè)問題開始医男,來談?wù)劜?..
    tangsl閱讀 4,088評(píng)論 0 23
  • Linux 進(jìn)程管理與程序開發(fā) 進(jìn)程是Linux事務(wù)管理的基本單元砸狞,所有的進(jìn)程均擁有自己獨(dú)立的處理環(huán)境和系統(tǒng)資源,...
    JamesPeng閱讀 2,449評(píng)論 1 14
  • 1 進(jìn)程介紹 1.1 進(jìn)程和程序 所謂進(jìn)程是由正文段(text)镀梭、用戶數(shù)據(jù)段(user segment)以及系統(tǒng)數(shù)...
    瘋狂小王子閱讀 1,225評(píng)論 0 7
  • fork丰辣,vfork撒强,cloneUnix標(biāo)準(zhǔn)的復(fù)制進(jìn)程的系統(tǒng)調(diào)用時(shí)fork(即分叉),但是Linux笙什,BSD等操作...
    Albert陳凱閱讀 1,382評(píng)論 0 0
  • 有沒有那么一個(gè)人 一直被你仰望著 連認(rèn)識(shí)他/她都覺得幸運(yùn)飘哨。 有沒有那么一個(gè)人 你相信他/她, 他/她也...
    阿微小主閱讀 160評(píng)論 0 0