Linux进程实践(2) --僵尸进程与文件共享
孤兒進程與僵尸進程
孤兒進程:
? ?如果父進程先退出,子進程還沒退出那么子進程的父進程將變為init進程。(注:任何一個進程都必須有父進程)
//生成孤兒進程 int main(int argc, char *argv[]) {pid_t pid = fork();if (pid < 0)err_exit("fork error");else if (pid > 0)exit(0);else{sleep(10);cout << "Child, ppid = " << getppid() << endl;}exit(0); }僵尸進程:
? ?如果子進程先退出,父進程還沒退出,那么子進程必須等到父進程捕獲到了子進程的退出狀態才真正結束,否則這個時候子進程就成為僵尸進程。
//生成僵尸進程 int main(int argc, char *argv[]) {pid_t pid = fork();if (pid < 0)err_exit("fork error");else if (pid == 0)exit(0);else{sleep(50);}exit(0); }附-查詢父子進程狀態
? ps?-le?|?grep?main
?
避免僵尸進程
? ?signal(SIGCHLD,?SIG_IGN);
//示例: 避免僵尸進程 int main(int argc, char *argv[]) {signal(SIGCHLD, SIG_IGN);pid_t pid = fork();if (pid < 0)err_exit("fork error");else if (pid == 0)exit(0);else{sleep(50);}exit(0); }文件共享
? ?父進程的所有文件描述符都被復制到子進程中,?就好像調用了dup函數,?父進程和子進程每個相同的打開文件描述符共享一個文件表項(因此,?父子進程共享同一個文件偏移量);
fork?VS?vfork
? 在UNIX/Linux中的fork還沒實現copy?on?write(寫時復制)技術之前。Unix設計者很關心fork之后立刻執行exec所造成的地址空間浪費,所以引入了vfork系統調用。其中,vfork子進程與父進程共享數據段,并不真正復制父進程內存,因此在vfork之后執行exec系列函數,并不會導致地址空間浪費以及無用的空間復制時間.而且,即使fork實現了copy?on?write,效率也沒有vfork高.
? 但是,vfork有個限制,子進程必須立刻執行_exit或者exec系列函數。因此我們不推薦使用vfork,因為幾乎每一個vfork的實現,都或多或少存在一定的問題(可以嘗試在vfork之后的子進程中既不執行_exit,也不執行exec函數)。
?
fork與vfork的區別
1. fork子進程拷貝父進程的數據段(但是現在提供了寫時復制技術,只有當子進程真正需要寫內存時,才復制出該內存的一段副本),因此,在父進程/子進程中對全局變量所做的修改并不會影響子進程/父進程的數據內容.
????vfork子進程與父進程共享數據段,因此父子進程對數據的更新是同步的;
2. fork父、子進程的執行次序是未知的,取決于操作系統的調度算法
? ? vfork:子進程先運行,父進程后運行;
//示例1:vfork出錯情況 //在Linux 2.6內核上會持續執行,不會退出 //而在Linux 3.13內核上, 則會引發core dump int main() {int iNumber = 0;pid_t pid = vfork();if (pid == -1){perror("fork");return -1;}else if (pid > 0){cout << "In Parent Program..." << endl;cout << "iNumber = " << iNumber << endl;cout << "pid = " << static_cast<int>(getpid());cout << "\t ppid = " << static_cast<int>(getppid()) << endl;//_exit(0);}else if (pid == 0){iNumber ++;cout << "In Child Program..." << endl;cout << "iNumber = " << iNumber << endl;cout << "pid = " << static_cast<int>(getpid());cout << "\t ppid = " << static_cast<int>(getppid()) << endl;//_exit(0);}return 0; }//示例2: 父進程/子進程修改全局數據的情況 int main() {int iNumber = 10;cout << "Before vfork, pid = " << getpid() << endl;//對比fork()pid_t pid = vfork();if (pid == -1)err_exit("fork");else if (pid > 0){sleep(4);cout << "Parent, iNumber: " << iNumber << endl;}else if (pid == 0){++ iNumber;cout << "Child, iNumber = " << iNumber << endl;_exit(0);}return 0; } //示例3:用vfork執行當前目錄下的hello程序 int main() {int iNumber = 0;pid_t pid = vfork();if (pid == -1){perror("fork");return -1;}else if (pid > 0){cout << "In Parent Program..." << endl;cout << "iNumber = " << iNumber << endl;cout << "pid = " << static_cast<int>(getpid());cout << "\t ppid = " << static_cast<int>(getppid()) << endl;}else if (pid == 0){iNumber ++;cout << "In Child Program..." << endl;cout << "iNumber = " << iNumber << endl;cout << "pid = " << static_cast<int>(getpid());cout << "\t ppid = " << static_cast<int>(getppid()) << endl;//將自己寫的程序啟動起來execve("./hello",NULL,NULL);_exit(0);}return 0; }
//測試4,用vfork執行系統命令 int main() {int iNumber = 0;pid_t pid = vfork();if (pid == -1){perror("fork");return -1;}else if (pid > 0){cout << "In Parent Program..." << endl;cout << "iNumber = " << iNumber << endl;cout << "pid = " << static_cast<int>(getpid());cout << "\t ppid = " << static_cast<int>(getppid()) << endl;}else if (pid == 0){iNumber ++;cout << "In Child Program..." << endl;cout << "iNumber = " << iNumber << endl;cout << "pid = " << static_cast<int>(getpid());cout << "\t ppid = " << static_cast<int>(getppid()) << endl;//將ls命令啟動起來,注意:由于C++嚴格的類型轉換機制,需要在字符串前加(char*)char *const args[] = {(char *)"/bin/ls", (char *)"-l", NULL};int res = execve("/bin/ls",args,NULL);if (res == -1){perror("execve");_exit(1);}_exit(0);}return 0; }
總結
以上是生活随笔為你收集整理的Linux进程实践(2) --僵尸进程与文件共享的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 海量数据处理专题(六)——双层桶划分
- 下一篇: JNLP(Java Web Start