Linux进程实践(2) --僵尸进程与文件共享
孤兒進(jìn)程與僵尸進(jìn)程
孤兒進(jìn)程:
? ?如果父進(jìn)程先退出,子進(jìn)程還沒(méi)退出那么子進(jìn)程的父進(jìn)程將變?yōu)閕nit進(jìn)程。(注:任何一個(gè)進(jìn)程都必須有父進(jìn)程)
//生成孤兒進(jìn)程 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); }僵尸進(jìn)程:
? ?如果子進(jìn)程先退出,父進(jìn)程還沒(méi)退出,那么子進(jìn)程必須等到父進(jìn)程捕獲到了子進(jìn)程的退出狀態(tài)才真正結(jié)束,否則這個(gè)時(shí)候子進(jìn)程就成為僵尸進(jìn)程。
//生成僵尸進(jìn)程 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); }附-查詢父子進(jìn)程狀態(tài)
? ps?-le?|?grep?main
?
避免僵尸進(jìn)程
? ?signal(SIGCHLD,?SIG_IGN);
//示例: 避免僵尸進(jìn)程 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); }文件共享
? ?父進(jìn)程的所有文件描述符都被復(fù)制到子進(jìn)程中,?就好像調(diào)用了dup函數(shù),?父進(jìn)程和子進(jìn)程每個(gè)相同的打開文件描述符共享一個(gè)文件表項(xiàng)(因此,?父子進(jìn)程共享同一個(gè)文件偏移量);
fork?VS?vfork
? 在UNIX/Linux中的fork還沒(méi)實(shí)現(xiàn)copy?on?write(寫時(shí)復(fù)制)技術(shù)之前。Unix設(shè)計(jì)者很關(guān)心fork之后立刻執(zhí)行exec所造成的地址空間浪費(fèi),所以引入了vfork系統(tǒng)調(diào)用。其中,vfork子進(jìn)程與父進(jìn)程共享數(shù)據(jù)段,并不真正復(fù)制父進(jìn)程內(nèi)存,因此在vfork之后執(zhí)行exec系列函數(shù),并不會(huì)導(dǎo)致地址空間浪費(fèi)以及無(wú)用的空間復(fù)制時(shí)間.而且,即使fork實(shí)現(xiàn)了copy?on?write,效率也沒(méi)有vfork高.
? 但是,vfork有個(gè)限制,子進(jìn)程必須立刻執(zhí)行_exit或者exec系列函數(shù)。因此我們不推薦使用vfork,因?yàn)閹缀趺恳粋€(gè)vfork的實(shí)現(xiàn),都或多或少存在一定的問(wèn)題(可以嘗試在vfork之后的子進(jìn)程中既不執(zhí)行_exit,也不執(zhí)行exec函數(shù))。
?
fork與vfork的區(qū)別
1. fork子進(jìn)程拷貝父進(jìn)程的數(shù)據(jù)段(但是現(xiàn)在提供了寫時(shí)復(fù)制技術(shù),只有當(dāng)子進(jìn)程真正需要寫內(nèi)存時(shí),才復(fù)制出該內(nèi)存的一段副本),因此,在父進(jìn)程/子進(jìn)程中對(duì)全局變量所做的修改并不會(huì)影響子進(jìn)程/父進(jìn)程的數(shù)據(jù)內(nèi)容.
????vfork子進(jìn)程與父進(jìn)程共享數(shù)據(jù)段,因此父子進(jìn)程對(duì)數(shù)據(jù)的更新是同步的;
2. fork父、子進(jìn)程的執(zhí)行次序是未知的,取決于操作系統(tǒng)的調(diào)度算法
? ? vfork:子進(jìn)程先運(yùn)行,父進(jìn)程后運(yùn)行;
//示例1:vfork出錯(cuò)情況 //在Linux 2.6內(nèi)核上會(huì)持續(xù)執(zhí)行,不會(huì)退出 //而在Linux 3.13內(nèi)核上, 則會(huì)引發(fā)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: 父進(jìn)程/子進(jìn)程修改全局?jǐn)?shù)據(jù)的情況 int main() {int iNumber = 10;cout << "Before vfork, pid = " << getpid() << endl;//對(duì)比f(wàn)ork()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執(zhí)行當(dāng)前目錄下的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;//將自己寫的程序啟動(dòng)起來(lái)execve("./hello",NULL,NULL);_exit(0);}return 0; }
//測(cè)試4,用vfork執(zhí)行系統(tǒng)命令 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命令啟動(dòng)起來(lái),注意:由于C++嚴(yán)格的類型轉(zhuǎn)換機(jī)制,需要在字符串前加(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; }
總結(jié)
以上是生活随笔為你收集整理的Linux进程实践(2) --僵尸进程与文件共享的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 海量数据处理专题(六)——双层桶划分
- 下一篇: JNLP(Java Web Start