gpt4 book ai didi

linux - 为什么用 fork() 和 exec() 创建的进程的 pid 最终改变了

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:15:50 24 4
gpt4 key购买 nike

我用 fork 和 exec 启动一个进程,但是当我使用 ps 时,比如 ps afx | grep sublime 查看pid,发现这两个pid(一个是fork()的返回值,一个是ps的结果)是不一样的。

我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int create_process(char *name, char *argv[])
{
int pid = fork();
if (0 == pid)
{
execv(name, argv);
exit(127);
}
else if (0 < pid)
{
return pid;
}else
{
return -1;
}
}

int forkstyle_system(char *cmdstring)
{
int pid = fork();
if (0 == pid)
{
execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
exit(127);
}
else if (0 < pid)
{
return pid;
}
else
{
return -1;
}
}

int main()
{
//method 1
char *name = "/opt/sublime_text/sublime_text";
char *argv[] = {"/opt/sublime_text/sublime_text", (char *)0};
int pid = create_process(name, argv);
printf("pid = %d\n",pid);

//method 2
/*
char *cmdstring = "/opt/sublime_text/sublime_text";
int pd = forkstyle_system(cmdstring);
printf("pid = %d\n",pd);
*/
return 0;
}

方法一的结果

enter image description here

方法二的结果

enter image description here

我感到很困惑,因为我认为,在 child 身上,execv()的使用是无关紧要的;这不会改变 pid。

最佳答案

看起来 @Barmar 在这里是正确的...内部 sublime text 正在创建一个(好吧...肯定不止一个) child ...很可能是 fork() .您可以从下面的 clone 调用中看出 sublime 正在创建 child 。

[acripps@localhost Code]$ strace -e trace=%process /opt/sublime_text/sublime_text 
execve("/opt/sublime_text/sublime_text", ["/opt/sublime_text/sublime_text"],
0x7ffff4607370 /* 56 vars */) = 0
arch_prctl(ARCH_SET_FS, 0x7fb6fa15b740) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD,
child_tidptr=0x7fb6fa15ba10) = 32653
exit_group(0) = ?
+++ exited with 0 +++

在这里我们可以看到 pids,如问题中所述。请注意 strace 中的 child_tidptr 值:它对应于 sublime 的实际 PID,而不是

[acripps@localhost Code]$ ps afx | grep sublime
32675 pts/0 S+ 0:00 | | \_ grep --color=auto sublime
32653 ? Ssl 0:00 \_ /opt/sublime_text/sublime_text
32670 ? Sl 0:00 \_ /opt/sublime_text/plugin_host 32653 --auto-shell-env
[acripps@localhost Code]$

如果您要使用一些更简单的东西,例如 sleep,您会发现 pids 符合您的期望:

[acripps@localhost Code]$ ./exec_m1 
pid = 1696
Press ENTER to continue ...
[acripps@localhost Code]$ ps afx | grep sleep
1696 pts/1 S+ 0:00 | | \_ /usr/bin/sleep 300
1711 pts/2 S+ 0:00 | \_ grep --color=auto sleep

或者,使用方法 2:

[acripps@localhost Code]$ ./exec_m2
pid = 1774
Press ENTER to continue ...
[acripps@localhost Code]$ ps afx | grep sleep
1774 pts/1 S+ 0:00 | | \_ /usr/bin/sleep 300
1776 pts/2 S+ 0:00 | \_ grep --color=auto sleep

值得注意的一点是,您在方法 2 中使用了 "/bin/sh -c" ... 这一步应该不是必需的。 IIRC,当没有附加到 tty 时,shell 将简单地调用 exec 函数族之一来用可执行文件替换自身......如果 shell 附加到一个不过,TTY 会先进行另一个 fork 调用。

POSIX spec 中有很多非常好的信息,但可能需要多读几遍才能真正理解……此外,检查 POSIX 操作系统的源代码并尝试理解进程管理部分确实有助于巩固理解。我用 QNX neutrino 完成了这项工作,但 FreeBSD 是另一个值得一试的好软件。

对于这个练习,我稍微修改了你的 main() 函数,使其更易于使用:

int main()
{
int pid = 0;

#if METHOD == 1
//method 1
char *name = "/usr/bin/sleep";
char *argv[] = {name, "300", (char *)0};
pid = create_process(name, argv);
#else
#if METHOD == 2
//method 2
char *cmdstring = "/usr/bin/sleep 300";
pid = forkstyle_system(cmdstring);
#endif
#endif

printf("pid = %d\n",pid);
printf("Press ENTER to continue ...");
getchar();
return 0;
}

可以这样编译:

gcc -o exec_method1 -DMETHOD=1 exec.c
gcc -o exec_method2 -DMETHOD=2 exec.c

...我懒惰并使用了预处理器,理想情况下(如果这是你想要保留的工具的开始),那么你会想要解析 main argv 告诉您使用哪种方法,以及在哪里可以找到可执行文件/为可执行文件提供参数。我把它留给读者作为练习 ;-)

关于linux - 为什么用 fork() 和 exec() 创建的进程的 pid 最终改变了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52062862/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com