模拟实现——僵尸和孤儿进程

本文深入探讨了僵尸进程和孤儿进程的概念,解释了僵尸进程如何产生及潜在危害,包括内存泄漏的风险;同时,介绍了孤儿进程的特性,即父进程先于子进程退出,子进程由init进程接管,通常不会造成系统危害。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 、僵尸进程

 1.   我们知道进程状态有:R运行状态,S睡眠状态(可中断睡眠状态),D磁盘休眠状态(不可中断睡眠状态),T停止状态,X死亡状态。还有一种比较特殊的就是僵尸状态(Z)了。

 2.    Z(zombie)--僵尸进程

    <1>当子进程退出,父进程无法读取到子进程退出的返回码时就会产生僵尸进程。父进程还在运行,子进程进入僵尸状态。

    <2>僵尸进程以进程中止的状态保持在进程表中,并且一直会等待父进程读取退出状态代码。

下面我们来实现一个简单的僵尸进程:

test.c代码部分:

1 #include<stdio.h>
  2 #include<stdlib.h>
  3 
  4 int main()
  5 {
  6     pid_t id=fork();
  7     if(id < 0){
  8         //error
  9         perror("fork");
 10         return 1;
 11     }
 12     else if( id == 0 ){//child
 13         printf("child[%d] is begin Z!!!\n",getpid());
 14         sleep(5);
 15         exit(EXIT_SUCCESS);
 16     }
 17     else{//parent
 18         printf("parent[%d] is sleeping!!!\n",getpid());
 19         sleep(30);
 20     }
 21 
 22     return 0;
 23 }

makefile:

  1 test:test.c                                                                                                                                              
  2     gcc -o test test.c
  3 
  4 .PHONY:clean
  5 clean:
  6     rm -f test

在此终端下编译代码:

编译时在另一个终端启动监控:

我们可以看到 ,子进程在睡眠后退出,由于父进程不读取其退出状态,子进程进入Z状态。

3.僵尸进程的危害

   <1>我们知道,父进程创建出子进程,是想让子进程完成某项工作,那么子进程退出时就要告诉父进程,你交给我的工作,我完成的如何。可是如果父进程一直不读取子进程的退出状态,那么子进程就会一直处于Z状态。因此,进程的退出状态必须被维持下去。

维护进程的退出状态本质上是要用数据维护,这个数据也属于进程信息,因此数据会保存在PCB中。如果Z状态一直不退出,那么PCB就要一直维护进程的退出状态。

如果一个进程创建出很多子进程,但它就是不读取子进程的退出状态,那么由于PCB占用内存,只开辟空间而不回收就会造成内存资源的浪费,进而造成内存泄漏。因此,父进程要及时回收子进程,避免内存泄漏,对系统造成威胁。

二、 孤儿进程

1.父进程先退出,子进程就被称为“孤儿进程”。

     父进程退出后,子进程被1号进程init领养,init进程对孤儿进程完成状态收集工作。

实现:

  1 #include<stdio.h>                                                                                                                                        
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 
  5 int main()
  6 {
  7     pid_t id =fork();
  8     if(id < 0){
  9         perror("fork");
 10         exit(0);
 11     }
 12     else if(id > 0){//parent
 13         printf("I am parent,pid:%d\n",getpid());
 14         sleep(5);
 15         exit(0);
 16     }
 17     else{//child
 18         printf("I am child,pid:%d\n",getpid());
 19         sleep(10);
 20         exit(0);
 21     }
 22     return 0;
 23 }

编译并且在另一个终端启动监控:

可以看出,当父进程退出后,子进程的ppid变为了1,这样,当一个孤儿进程结束了其生命周期的时候,init进程就会处理它的一切善后工作,因此一般来说,孤儿进程不会有什么危害。

### 关于线程子线程的代码示例 在线程编程中,通常会涉及主线程子线程之间的交互。以下是基于 POSIX Windows 平台上的两个简单代码示例。 #### POSIX 线程示例 此代码展示了如何创建一个简单的子线程,并通过 `pthread_join` 来等待子线程完成[^1]: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> void* thread_function(void* arg) { printf("子线程正在运行\n"); sleep(2); return (void*)0; } int main() { pthread_t thread_id; if (pthread_create(&thread_id, NULL, thread_function, NULL)) { fprintf(stderr, "无法创建线程\n"); exit(EXIT_FAILURE); } printf("主线程继续执行其他任务...\n"); void* result; if (pthread_join(thread_id, &result)) { fprintf(stderr, "无法加入线程\n"); exit(EXIT_FAILURE); } printf("子线程已完成\n"); return EXIT_SUCCESS; } ``` #### Windows 线程示例 在此代码中,展示了一个基本的 Windows 子线程创建方式以及如何安全停止线程[^5]: ```cpp #include <windows.h> #include <iostream> DWORD WINAPI WorkerThread(LPVOID lpParam) { std::cout << "子线程正在运行..." << std::endl; Sleep(3000); // 模拟工作负载 std::cout << "子线程即将结束." << std::endl; return 0; } int main() { HANDLE hThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, NULL); if (!hThread) { std::cerr << "无法创建线程!" << std::endl; return -1; } std::cout << "主线程将继续执行..." << std::endl; WaitForSingleObject(hThread, INFINITE); // 主线程等待子线程完成 CloseHandle(hThread); std::cout << "子线程已成功退出." << std::endl; return 0; } ``` --- ### 僵尸线程的概念及解释 当一个线程在其生命周期结束后未能正确释放其资源时,就会形成所谓的“僵尸线程”。具体来说,在 POSIX 系统中,默认情况下创建的线程是非分离状态的。这意味着即使这些线程已经完成了它们的任务,如果没有显式调用 `pthread_join()` 函数来回收它们的资源,则它们的状态仍然会被保留直到程序结束[^1]。这种残留状态即被称为僵尸线程。 为了避免这种情况的发生,可以通过两种主要途径解决问题:一是使用 `pthread_join()` 方法手动收集每个终止后的非分离态线程所占用的空间;二是利用 `pthread_detach()` 将某个特定线程标记为可自动清理模式下运作——一旦这样的线程结束了自身的生命期之后就不会再留下任何痕迹给操作系统去管理了[^4]。 需要注意的是,在某些平台上(如 Linux/Unix),如果主线程提前退出而没有适当处理好所有存活中的子线程的话,那么整个进程可能会被强制销毁或者遗留下来的那些未 join/detach 的子线程有可能转变为孤立存在的实体形式存在下去成为真正的孤儿进程或伪死锁现象的一部分。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值