如果您知道进程的pid,有没有办法销毁从该进程创建的孔进程树并释放这些进程分配的所有内存?我需要找到一种方法在 C 程序中做到这一点,而不必转到树的每个进程。
所以这是我在阅读巴西尔·斯塔林克维奇后制作的代码非常有用的答案.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
void proctreecreator(int count);
int main()
{
int status,count;
count = 0;
pid_t pid,procapid;
pid = fork();
if (pid < 0) {
perror("main: fork");
exit(1);
}
if (pid == 0)
{
if( setpgid(0,0) <0 ) perror( "main: setpgid" );
proctreecreator(count);
exit(1);
}
procapid=pid;
pid = fork();
if (pid < 0) {
perror("main: fork");
exit(1);
}
if (pid == 0)
{
sleep(1);
printf("I will now destroy the process tree n");
kill(-procapid, SIGTERM);
exit(0);
}
procapid = waitpid(procapid, &status, 0);
if (procapid < 0) perror( "main: waitpid" );
else printf("Process A and its tree are killedn");
pid = waitpid(pid, &status, 0);
if (pid < 0) perror("main: waitpid");
else printf("process B exited n");
return 0;
}
void proctreecreator(int count)
{
pid_t pid;
int status,i;
int *k = (int*)malloc(sizeof(int));
*k=count;
pid_t mypid=getpid();
printf("process with pid : %d created in depth %d n",mypid,count);
if (count > 3)
{
sleep(5);
free(k);
exit(0);
}
else
{
count++;
pid = fork();
if (pid < 0) {
perror("proctreecreator: fork");
exit(1);
}
if (pid == 0)
{
proctreecreator(count);
exit(1);
}
pid = fork();
if (pid < 0) {
perror("proctreecreator: fork");
exit(1);
}
if (pid == 0)
{
proctreecreator(count);
exit(1);
}
for (i=0; i<2; i++)
{
pid = wait(&status);
if (pid < 0) perror("proctreecreator: wait");
else printf("process %d is now terminated",pid);
}
free(k);
exit(0);
}
}
我对程序的工作原理有一些疑问!当使用kill(-procapid,SIGTERM)时;销毁进程树需要恒定的时间还是取决于树的大小? 所有分配的内存在杀死后是否都可用(-procapid,SIGTERM);
?当一个进程终止时,它使用的所有虚拟内存 - 包括通常由malloc
&free
管理的堆,通常通过mmap(2)等...- 已释放(共享内存除外)。
(强制)终止其他进程的系统调用是 kill(2),它准确地向进程(或进程组)发送信号。读取信号(7)。如果进程树中的所有进程都属于同一进程组(请参阅 credentials(7) ...),则只需kill
该进程组。参见 killpg(2)。
您应该首先kill
SIGTERM
.这为行为良好的程序(如许多RDBMS服务器)提供了适当处理该信号的机会(例如释放资源,清理等)。一秒钟后,你可以kill
SIGQUIT
.最后,您可以发送无法捕获且始终终止进程的SIGKILL
信号。
另请阅读有关会话和 setsid(2)(以及进程组的 setpgid(2))和控制终端的信息。另请参阅tty揭秘页面和作业控制维基页面。
请注意,某些处理仍可继续。想象一下,你的一些进程是 execve(2) batch(1),即/usr/bin/batch
(或ssh
)
所以你的第一个程序分叉了一些A
;让它调用setpgid(0,0)
(参见 setpgid(2) 了解详情)。当然,你的第一个程序需要保留 pid 的A
(由 fork(2) 返回),让我们假设它在pid_t pid_of_A
中;然后你需要稍后kill(-pid_of_A, SIGTERM)
,最后waitpid(pid_of_A, &status_of_A, 0)
(参见waitpid(2)...)。
阅读高级 Linux 编程
您已通过添加以下内容编辑了您的问题:
对程序的工作原理有一些疑问!使用
kill(-procapid, SIGTERM)
时;销毁进程树需要恒定的时间还是取决于树的大小?
这确实应该是另一个问题。杀死进程组时kill
的理论复杂性在实践中不应该打扰你。原因是在实践中你没有很多(正在运行的)进程;除非你在一台价值数百万美元的超级计算机上运行,否则你只希望有几十个正在运行的进程(否则你的整个系统和机器将过载并开始崩溃)。因此,杀死进程树的实际复杂性并不重要,因为在实践中,您的进程树只有几十个正在运行的进程(总共有几百个进程,其中大多数是空闲的)。
你也问
kill(-procapid, SIGTERM);
后分配的所有内存都可用吗?
阅读更多关于进程、分叉系统调用、分叉炸弹的信息。请理解每个进程都使用虚拟内存并有自己的地址空间,malloc
使用 例如 mmap(2) 来更改正在运行的进程的地址空间(仅)。
当进程终止时,内核将删除其整个地址空间。这与kill(
没有直接关系...SIGTERM)
因为某些进程会捕获SIGTERM
以进行有用的清理。(换句话说,将SIGTERM
发送到某个进程并不总是会立即终止它)。
高级Linux编程正在详细解释这一点,比我必须做的要好得多。
是的,创建一个进程(使用 fork(2)),终止一个进程(因为某些终止信号(7) 或因为它轻轻地_exit(2)-ed),用进程中的另一个程序替换正在运行的程序(使用 execve(2) ...),以及更改正在运行的进程的地址空间(使用malloc
经常使用的 mmap(2) ...)是复杂且昂贵的操作, 但是Linux内核做得很好。
流程是相当广泛的资源,所以你不应该有很多。因此,渐近复杂性不是推理它们的正确概念。您希望拥有"少数"("少数"的含义取决于您的特定系统和硬件)。现在我的 i3770K Linux/Debian 桌面(具有 16GB RAM)有 238 个进程,其中大多数处于空闲状态(在终端中ps auxw
运行以找出答案),只有少数正在运行。最近的 Linux 内核有一个高效的调度器,通常是 O(1) 调度器。
有传言说Linux非常擅长管理进程,在Linux上创建进程被认为比在Windows上更快。