C语言 僵尸进程

mv1qrgav  于 2023-08-03  发布在  其他
关注(0)|答案(5)|浏览(117)

我有一些关于僵尸进程的问题

  • 僵尸进程概念的好处是什么?
  • 我知道内核为僵尸进程保留了(PID、终止状态、资源使用信息)

“资源使用信息”是什么意思

  • zombie的PPID()= 1,但它仍然是zombie,(init捕获Zombie,因为默认情况下它是wait())

任何人都可以写一些C代码来创建一个僵尸,它的父节点是Init?

  • 僵尸会拒绝释放记忆锁吗?

提前致谢

ki1q1bka

ki1q1bka1#

--僵尸流程概念有什么好处?
僵尸进程只是一个pid、一个退出状态和一些会计信息,这些信息一直存在,直到父进程使用wait系列系统调用之一来获取其最终状态。在父进程调用wait之前,子进程的进程ID必须保持标记为已使用,这样其他进程就不能分配它。如果另一个进程被分配了一个回收的pid,那么很难区分它和以前具有相同pid的进程之间的区别。一旦父进程调用wait并返回最终退出状态,就可以假定没有人会再去那个pid上查找子进程,所以现在可以重用这个pid了。(我认为在Linux上,如果父代将SIGCHLD作为SIG_IGN离开,内核将不会保持僵尸,但将SIGCHLD的处置重新注册为SIG_IGN不会产生相同的效果)
--知道内核为僵尸进程保存(PID,终止状态,资源使用信息)“资源使用信息”的含义是什么
其中一些信息是运行程序的内容:

time my_program

字符串
将报告。这些值通常在SIGCHLD的siginfo结构中报告(这并不完全是对wait的调用),但也可以从对waitid形式的systme调用的调用中获得(在某些系统上)。查看man sigaction以了解有关此结构的信息。
-- how zombie's PPID()= 1 and it still zombie,(init reaps Zombies because it wait()by default)
一个ppid = 1的zombie不应该保持很长时间的zombie状态,因为 init 应该很快就能获得它。一个进程在死亡后不久(通过exit或通过一个非手动信号杀死它),直到它的父进程调用wait并获得它的最终状态为止。这意味着即使init什么也不做,只是一遍又一遍地调用init,也可能有一小段时间进程可能显示为僵尸。如果进程长时间(秒)显示为 init(0=ppid)的子进程,那么可能有问题。
--任何人都可以写一些C代码,使一个僵尸它的父是Init?
这不是很清楚,但我认为你想要:

pid_t f = fork();
if (f > 0) {
    exit(0); // this is the parent dying, so the child will be an orphan
             // and get adopted by init
} else if (f == 0) {
    sleep(100); // This is the child doing something that takes enough time for
                // its parent to commit suicide (exit(0)) and then for you to
                // observe that it has now been adopted by init
    exit(0);    // And now it dies as well, so init should reap its status, but
                // it may be a zombie for a short amount of time first.
} else /* error condition would be handled here */


--僵尸可以拒绝释放一些锁定的记忆吗??
僵尸什么都抓不住。它们会丢失所有的内存页、打开的文件句柄等。几乎所有操作系统能弄清楚如何释放的东西都应该被释放。这将是一个错误,但请记住,操作系统必须知道,这是应该被释放的东西。在用户空间中创建资源是非常容易的,当一个程序死亡时,操作系统不知道应该释放这些资源。

igetnqfo

igetnqfo2#

僵尸进程纯粹是一个pid和退出状态值。无法释放pid,因为资源(pid)“属于”父级。如果它被释放,另一个进程可能被分配相同的pid,然后父进程可能最终向不相关的进程发送信号;即使父节点首先等待确定子节点是否已经退出,也没有办法避免竞争条件。

slmsl1lt

slmsl1lt3#

如果你想在一个正在运行的进程列表中看到僵尸进程,可以使用这个:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main(void)
{
    pid_t p = fork();   // creates child process and stores the returned PID

    if (p != 0)         // executed by parent process
    {   sleep(1);       /* the child process terminates while the parent process sleeps,
                           the child then becomes a zombie process because the returned status
                           of the terminated child process isn't checked via a wait() */

        system("ps -eo pid,ppid,stat,cmd");  // prints a list of processes in your terminal

    }
    else        // executed by child process
    {
        exit(0);        // the child process terminates immediately
    }

    return 0;
}

字符串
您可以通过列表中的Z+来识别僵尸进程:


的数据
注意:如果您使用的是Windows,则必须修改代码。

5uzkadbs

5uzkadbs4#

僵尸进程是已经停止运行的进程,但它们的进程表条目仍然存在,因为父进程还没有通过等待系统调用检索到它。从技术上讲,每个终止的进程在很短的一段时间内都是僵尸,但它们可以存活更长时间。
当父进程在子进程完成后没有调用wait syscall时,会出现更长时间的僵尸进程。发生这种情况的一种情况是,父进程编写得很差,只是省略了wait调用,或者父进程在子进程之前死亡,新的父进程没有调用wait。当进程的父进程在子进程之前死亡时,OS将子进程分配给“init”进程或PID 1。也就是说,init进程“采用”子进程并成为其父进程。这意味着现在当子进程退出时,新的父进程(init)必须调用wait来获取它的退出代码,否则它的进程表条目将永远保留,它将变成僵尸进程

wlwcrazw

wlwcrazw5#

僵尸进程不是一个有生命的东西,所以它们不能被杀死。其目的主要有三个原因:
1.在父进程保持活动状态并且不执行wait()系统调用时,维护分配的pid号,以防止其他fork()分配它并避免pid冲突。这种分配也避免(间接地)创建具有该id号的进程组和会话。PID分配需要遍历进程表,以检查候选pid是否已在使用中,因此为行尸走肉进程维护进程表条目是一个好主意。
1.将exit()值或状态信息(如果已终止)存储到进行wait()系统调用的父进程。
1.临时存储有关运行时间(进程累积的系统/用户时间)的记帐信息。今天的操作系统在这里存储的不仅仅是这个记帐信息,还有更多(交换、系统调用次数等)
这个解决方案是如此巧妙,以至于自从它在AT&T unix中首次实现以来,没有人认为它应该被改变。顺便说一下,除了进程表条目之外,没有系统资源被分配给它们,因为所有这些信息都存储在那里,所以没有内存或文件描述符的影响是由于这些进程。他们也被排除在日程表之外,所以他们不能再站起来走路。
zombie的PPID()= 1,但它仍然是zombie,(init捕获Zombie,因为默认情况下它是wait())有人能写一些C代码来创建一个zombie吗?
有可能init()还没有花时间进行wait()系统调用,它仍然在处理它所占的最后一个wait()。另一个原因是你指定了另一个 catchall 进程(linux允许这样做)而不是init。只有当一个Zombie进程发出exit()系统调用或被一个信号杀死时,它才会被重新指定为等待它的进程的父进程。在负载很重的系统中,您可以看到PPID为1的僵尸进程,但这并不常见。
僵尸会拒绝释放记忆锁吗?
僵尸只是进程表条目。属于僵尸进程的所有资源都已经返回到系统(进程只有在释放完所有资源后才进入僵尸状态),所以僵尸进程不能持有任何资源锁(原因很简单,它已经死了,所以它不能释放它)
设想一个复杂的场景,其中一个进程获取了一个tcpip套接字,并且该套接字处于连接状态。然后,该进程被一个信号杀死,成为僵尸,而套接字仍然是活的(并且释放该套接字仍需要运行协议交换来关闭连接)在这种情况下,过程资源实际上被释放(这意味着与套接字关联的文件描述符)但是套接字关闭被传递给TCP内核线程,该线程将继续由内核在释放僵尸资源时进行的隐式close()调用启动的工作。如果没有专用于此目的的内核线程,那么该进程将仍然处于释放资源的过程中-并显示为活动的-直到释放完成。一旦所有资源都从死亡进程中解绑/释放,它将被标记为僵尸(尸体可能是一个更好的术语)释放资源的任务是在系统时间内完成的,因此进程无法对其进行控制,也没有附加信号处理程序或其他任何东西。一旦进程死亡,它就会死亡。

相关问题