19:22:01 2014-08-27
引言:
以前對wait waitpid 以及exit這幾個函數只是大致上了解,但是看REDIS的AOF和RDB 2種持久化時 均要處理子進程運行完成退出和父進程需要做的什麼事情,所以特定看了UNIX環境編程和LINUX系統編程這2本書 重新梳理下整個要點。
內容:
一般而言: 如果程序類似於下面的情況:
if((pid=fork())==0) { dochildtthing(); exit(0); } else if(pid>0) { dofathertthing(); }
子進程就會調用了我們進程退出系統調用exit()分為2種狀態 0: 成功 非0:失敗
exit需要做以下事情:
1: 關閉所有打開的IO流
2 刪除所有的臨時文件
1 2是傳說中用戶態需要完成的事情 接下來就調用_exit() 【這個函數在用戶態下 是被exit()封裝起來的函數】觸發內核來完成進程退出的相關工作
接下來就是清空所有的子進程所需要的資源哦 最後完成了 就會發送一個進程退出狀態【信號】給父進程 父進程做什麼處理就是編程人員完成的。
子進程發送的信號是SIGCHLD 一般而言就像REDIS fork()了一個進程之後 子進程完成了相應的持久化動作之後,父進程需要了解子進程一些狀態來做相應的處理工作,所以在LINUX系統中,這個子進程退出後 還有一個標記位 我們稱作zombie進程。父進程必須來取子進程的相應zombie的相應標記信息 不然是不會消除的。
所以對於父進程而言,必須調用相應的函數【首先是注冊了SIGCHLD】處理這些標記位哦 wait/waitpid就是干這種事情。我們來看看這系列的調用所要做的事情:
1 #include <unistd.h> 2 #include <stdio.h> 3 #include <sys/types.h> 4 #include <sys/wait.h> 5 #include <stdlib.h> 6 7 int main() 8 { 9 int status; 10 pid_t pid; 11 if(fork()==0) 12 { 13 abort(); 14 } 15 pid=wait(&status); 16 printf("pid=%d\n",pid); 17 if(WIFEXITED(status)) 18 printf("正常退出\n"); 19 if(WIFSIGNALED(status)) 20 printf("killed by signal\n"); 21 return 0; 22 }
wait等待子進程掛 結果可以讀出子進程是被信號量終止了 所以說 讀出子進程的狀態還是非常有實際意義的~!
接下來看看wait/waitpid函數的區別:
如果有多個子進程 我該怎麼辦 要麼選擇多個wait 但是同時到達 可能就會處理一個子進程 而其他進程狀態沒有被處理 造成了很多zombie進程 這是不行的 這樣就有了waitpid函數:
waitpid(pid_t pid,int *status,int options)
pid=-1 等待任意一子進程
>0 要傳入的那個子進程
參數:
WNOHANG: 不會阻塞 立刻返回。 其他參數暫時不去研究了
這樣如果有這種 while(waitpid(-1,&stat,WNOHANG)>0);
這樣就能接受到所有的子進程的SIGCHLD了。 wait只執行一次 而Linux信號不排隊 同時到達 也只會處罰一次哦 這個必須要了解 這樣通過waitpid循環來解決掉,但是如果不指定WNOHANG的話 又比較麻煩 主進程會阻塞 這不是我們所想要的哦 所以必須解阻塞。
可能在持久化操作時要用到fork出的新進程,子進程完全拷貝了父進程,maxmemory可能是指所有進程的memory,所以只有一半內存。