?文章來源地址http://www.zghlxwxcb.cn/news/detail-475591.html
?文章來源:http://www.zghlxwxcb.cn/news/detail-475591.html
目錄
進程創(chuàng)建
fork函數(shù)初識
fork函數(shù)返回值
寫時拷貝
fork常規(guī)用法
fork調(diào)用失敗的原因
進程終止
進程退出場景
進程常見退出方法
_exit函數(shù)
exit函數(shù)
return退出
進程等待
進程等待必要性
進程等待的方法
wait方法
waitpid方法
獲取子進程status
進程程序替換
替換原理
替換函數(shù)
進程創(chuàng)建
fork函數(shù)初識
在linux中fork函數(shù)時非常重要的函數(shù),它從已存在進程中創(chuàng)建一個新進程。新進程為子進程,而原進程為父進程。
#include <unistd.h>
pid_t fork(void);
返回值:子進程中返回0,父進程返回子進程id,出錯返回-1
進程調(diào)用fork,當控制轉(zhuǎn)移到內(nèi)核中的fork代碼后,內(nèi)核做:
分配新的內(nèi)存塊和內(nèi)核數(shù)據(jù)結(jié)構(gòu)給子進程
將父進程部分數(shù)據(jù)結(jié)構(gòu)內(nèi)容拷貝至子進程
添加子進程到系統(tǒng)進程列表當中
fork返回,開始調(diào)度器調(diào)度
當一個進程調(diào)用fork之后,就有兩個二進制代碼相同的進程。而且它們都運行到相同的地方。但每個進程都將可以開始它們自己的旅程。
fork之前父進程獨立執(zhí)行,fork之后,父子兩個執(zhí)行流分別執(zhí)行。注意,fork之后,誰先執(zhí)行完全由調(diào)度器決定。
fork函數(shù)返回值
子進程返回0,父進程返回的是子進程的pid。
寫時拷貝
通常,父子代碼共享,父子不寫入時,數(shù)據(jù)也是共享的,當任意一方試圖寫入,便以寫時拷貝的方式各自一份副本。
fork常規(guī)用法
一個父進程希望復制自己,使父子進程同時執(zhí)行不同的代碼段。例如,父進程等待客戶端請求,生成子進程來處理請求。
一個進程要執(zhí)行一個不同的程序。例如子進程從fork返回后,調(diào)用exec函數(shù)。
fork調(diào)用失敗的原因
系統(tǒng)中有太多的進程
實際用戶的進程數(shù)超過了限制‘
進程終止
進程退出場景
代碼運行完畢,結(jié)果正確
代碼運行完畢,結(jié)果不正確
代碼異常終止
進程常見退出方法
正常終止(可以通過 echo $? 查看進程退出碼):
1. 從main返回
2. 調(diào)用exit
3. _exit
異常退出:
ctrl + c,信號終止
_exit函數(shù)
#include <unistd.h>
void _exit(int status);
參數(shù):status 定義了進程的終止狀態(tài),父進程通過wait來獲取該值
雖然status是int,但是僅有低8位可以被父進程所用。所以_exit(-1)時,在終端執(zhí)行$?發(fā)現(xiàn)返回值
是255
exit函數(shù)
?#include <unistd.h>
void exit(int status);
exit最后也會調(diào)用exit, 但在調(diào)用exit之前,還做了其他工作:
1. 執(zhí)行用戶通過 atexit或on_exit定義的清理函數(shù)。
2. 關閉所有打開的流,所有的緩存數(shù)據(jù)均被寫入
3. 調(diào)用_exit
int main()
{
????????printf("hello");
????????exit(0);
}
運行結(jié)果:
[root@localhost linux]# ./a.out
hello[root@localhost linux]#
int main()
{
????????printf("hello");
????????_exit(0);
}
運行結(jié)果:
[root@localhost linux]# ./a.out
[root@localhost linux]#
return退出
return是一種更常見的退出進程方法。執(zhí)行return n等同于執(zhí)行exit(n),因為調(diào)用main的運行時函數(shù)會將main的返回值當做 exit的參數(shù)。?
進程等待
進程等待必要性
子進程退出,父進程如果不管不顧,就可能造成‘僵尸進程’的問題,進而造成內(nèi)存泄漏。另外,進程一旦變成僵尸狀態(tài),那就刀槍不入,“殺人不眨眼”的kill -9 也無能為力,因為誰也沒有辦法殺死一個已經(jīng)死去的進程。
最后,父進程派給子進程的任務完成的如何,我們需要知道。如,子進程運行完成,結(jié)果對還是不對,或者是否正常退出。
父進程通過進程等待的方式,回收子進程資源,獲取子進程退出信息
進程等待的方法
wait方法
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int*status);
返回值:
成功返回被等待進程pid,失敗返回-1。
參數(shù):
輸出型參數(shù),獲取子進程退出狀態(tài),不關心則可以設置成為NULL
waitpid方法
pid_ t waitpid(pid_t pid,? ? int *status,? ? int options);
返回值:
當正常返回的時候waitpid返回收集到的子進程的進程ID;
如果設置了選項WNOHANG,而調(diào)用中waitpid發(fā)現(xiàn)沒有已退出的子進程可收集,則返回0;
如果調(diào)用中出錯,則返回-1,這時errno會被設置成相應的值以指示錯誤所在;
參數(shù):
pid:
Pid=-1,等待任一個子進程。與wait等效。
Pid>0.等待其進程ID與pid相等的子進程。
status:
WIFEXITED(status): 若為正常終止子進程返回的狀態(tài),則為真。(查看進程是否是正常退出)
WEXITSTATUS(status): 若WIFEXITED非零,提取子進程退出碼。(查看進程的退出碼)
options:
WNOHANG: 若pid指定的子進程沒有結(jié)束,則waitpid()函數(shù)返回0,不予以等待。若正常結(jié)束,則返回該子進程的ID。
如果子進程已經(jīng)退出,調(diào)用wait/waitpid時,wait/waitpid會立即返回,并且釋放資源,獲得子進程退出信息。
如果在任意時刻調(diào)用wait/waitpid,子進程存在且正常運行,則進程可能阻塞。
如果不存在該子進程,則立即出錯返回
獲取子進程status
wait和waitpid,都有一個status參數(shù),該參數(shù)是一個輸出型參數(shù),由操作系統(tǒng)填充。
如果傳遞NULL,表示不關心子進程的退出狀態(tài)信息。
否則,操作系統(tǒng)會根據(jù)該參數(shù),將子進程的退出信息反饋給父進程。
status不能簡單的當作整形來看待,可以當作位圖來看待,具體細節(jié)如下圖(只研究status低16比特位):?
?
進程程序替換
替換原理
用fork創(chuàng)建子進程后執(zhí)行的是和父進程相同的程序(但有可能執(zhí)行不同的代碼分支),子進程往往要調(diào)用一種exec函數(shù)以執(zhí)行另一個程序。當進程調(diào)用一種exec函數(shù)時,該進程的用戶空間代碼和數(shù)據(jù)完全被新程序替換,從新程序的啟動例程開始執(zhí)行。調(diào)用exec并不創(chuàng)建新進程,所以調(diào)用exec前后該進程的id并未改變?
替換函數(shù)
?
#include <unistd.h>`
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 execve(const char *path, char *const argv[], char *const envp[]);
這些函數(shù)如果調(diào)用成功則加載新的程序從啟動代碼開始執(zhí)行,不再返回。
如果調(diào)用出錯則返回-1
所以exec函數(shù)只有出錯的返回值而沒有成功的返回值。
事實上,只有execve是真正的系統(tǒng)調(diào)用,其它五個函數(shù)最終都調(diào)用 execve?
? ? ??
? ? ? ? ?
?
?
?
?
到了這里,關于Linux操作系統(tǒng)——第二章 進程控制的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!