網(wǎng)站建設(shè)屬政府采購(gòu)項(xiàng)目嗎濟(jì)寧百度推廣公司
1.進(jìn)程創(chuàng)建
fork函數(shù)初識(shí)
在linux中fork函數(shù)時(shí)非常重要的函數(shù),它從已存在進(jìn)程中創(chuàng)建一個(gè)新進(jìn)程。新進(jìn)程為子進(jìn)程,而原進(jìn)程為父進(jìn)程。

返回值:子進(jìn)程返回0,父進(jìn)程返回子進(jìn)程id,出錯(cuò)返回-1
getpid()獲取子進(jìn)程id,getppid()獲取父進(jìn)程id
運(yùn)行程序,發(fā)現(xiàn)紅線的是父進(jìn)程的pid,而黃線的pid是bash進(jìn)程

進(jìn)程調(diào)用fork,當(dāng)控制轉(zhuǎn)移到內(nèi)核中的fork代碼后,內(nèi)核做:
分配新的內(nèi)存塊和內(nèi)核數(shù)據(jù)結(jié)構(gòu)給子進(jìn)程 將父進(jìn)程部分?jǐn)?shù)據(jù)結(jié)構(gòu)內(nèi)容拷貝至子進(jìn)程 添加子進(jìn)程到系統(tǒng)進(jìn)程列表當(dāng)中 fork返回,開始調(diào)度器調(diào)度

當(dāng)一個(gè)進(jìn)程調(diào)用fork之后,就有兩個(gè)二進(jìn)制代碼相同的進(jìn)程。而且它們都運(yùn)行到相同的地方。但每個(gè)進(jìn)程都將可以 開始它們自己的旅程,看如下程序。


這里看到了三行輸出,一行before,兩行after。進(jìn)程28358先打印before消息,然后它有打印after。另一個(gè)after 消息有28359打印的。注意到進(jìn)程28359沒有打印before,為什么呢?如下圖所示

所以,fork之前父進(jìn)程獨(dú)立執(zhí)行,fork之后,父子兩個(gè)執(zhí)行流分別執(zhí)行。注意,fork之后,誰先執(zhí)行完全由調(diào)度器 決定。所以第一個(gè)After返回的是父進(jìn)程pid,而子進(jìn)程返回0。
寫時(shí)拷貝
通常,父子代碼共享,父子再不寫入時(shí),數(shù)據(jù)也是共享的,當(dāng)任意一方試圖寫入,便以寫時(shí)拷貝的方式各自一份副 本。具體見下圖:

為什么要寫時(shí)拷貝,而不是直接創(chuàng)建進(jìn)程的時(shí)候拷貝一份呢?
操作系統(tǒng)不允許任何的浪費(fèi)內(nèi)存的行為,寫時(shí)拷貝本質(zhì)是按需申請(qǐng)資源的策略。
fork常規(guī)用法
1.一個(gè)父進(jìn)程希望復(fù)制自己,使父子進(jìn)程同時(shí)執(zhí)行不同的代碼段。例如,父進(jìn)程等待客戶端請(qǐng)求,生成子進(jìn)程來處理請(qǐng)求。
2.一個(gè)進(jìn)程要執(zhí)行一個(gè)不同的程序。例如子進(jìn)程從fork返回后,調(diào)用exec函數(shù)。
fork調(diào)用失敗的原因
1.系統(tǒng)中有太多的進(jìn)程
2.實(shí)際用戶的進(jìn)程數(shù)超過了限制
2.進(jìn)程終止
進(jìn)程退出場(chǎng)景
代碼運(yùn)行完畢,結(jié)果正確 代碼運(yùn)行完畢,結(jié)果不正確 代碼異常終止

進(jìn)程常見退出方法
1.正常終止(可以通過 echo $? 查看進(jìn)程退出碼):
1. 從main返回 2. 調(diào)用exit 3. _exit

$?:只會(huì)保留最近一次執(zhí)行的進(jìn)程的退出碼!

下面的程序是查看退出碼文件,strerror函數(shù)


不是所有的退出碼都遵循C語言,下面的退出碼1 No such process,C語言中退出碼是3

2.異常退出:
ctrl + c,信號(hào)終止
_exit函數(shù) :
#include <unistd.h>
void _exit(int status);
// 參數(shù):status 定義了進(jìn)程的終止?fàn)顟B(tài),父進(jìn)程通過wait來獲取該值
說明:雖然status是int,但是僅有低8位可以被父進(jìn)程所用。所以_exit(-1)時(shí),在終端執(zhí)行$?發(fā)現(xiàn)返回值 是255。
exit函數(shù) :
#include <unistd.h>
void exit(int status);
exit最后也會(huì)調(diào)用exit, 但在調(diào)用exit之前,還做了其他工作:
1. 執(zhí)行用戶通過atexit或on_exit定義的清理函數(shù)。
2. 關(guān)閉所有打開的流,所有的緩存數(shù)據(jù)均被寫入
3. 調(diào)用_exit

int main()
{printf("hello");exit(0);
}int main()
{printf("hello");_exit(0);
}

3.return退出
return是一種更常見的退出進(jìn)程方法。執(zhí)行return n等同于執(zhí)行exit(n),因?yàn)檎{(diào)用main的運(yùn)行時(shí)函數(shù)會(huì)將main的返 回值當(dāng)做 exit的參數(shù)。
如何理解進(jìn)程退出?
OS內(nèi)少了一個(gè)進(jìn)程,OS就要釋放進(jìn)程對(duì)應(yīng)的內(nèi)核數(shù)據(jù)結(jié)構(gòu)+代碼和數(shù)據(jù)