欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > linux >内容正文

linux

Linux进程实践(2) --僵尸进程与文件共享

发布时间:2025/3/17 linux 28 豆豆
生活随笔 收集整理的这篇文章主要介绍了 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函数, 父进程和子进程每个相同的打开文件描述符共享一个文件表项(因此, 父子进程共享同一个文件偏移量);


//根据上图: 理解下面这段程序和下图的演示 int main(int argc, char *argv[]) {signal(SIGCHLD, SIG_IGN);int fd = open("test.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666);if (fd == -1)err_exit("file open error");cout << "We Don`t flash memory\n";char buf[BUFSIZ];bzero(buf, sizeof(buf));pid_t pid = fork();if (pid < 0)err_exit("fork error");else if (pid > 0){strcpy(buf, "Parent...");write(fd, buf, strlen(buf));close(fd);cout << "fd = " << fd << endl;exit(0);}else if (pid == 0){strcpy(buf, "Child...");write(fd, buf, strlen(buf));close(fd);cout << "fd = " << fd << endl;exit(0);} }

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) --僵尸进程与文件共享的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。