我用fork和exec启动一个进程,但是当我使用ps
likeps 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;
}
方法1的结果
方法2的结果
我感到非常困惑,因为我认为,在孩子身上,execv()的使用是不相关的;这不会改变pid。
最佳答案
看起来,@barmar在这里是正确的…内部崇高的文本正在创造一个(嗯…这里肯定不止一个孩子……最有可能是fork()
。从下面的clone
调用可以看出sublime正在创建子级。
[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中微子做了这个,但是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
'sargv
来告诉您要使用哪种方法,以及在哪里找到可执行文件/为可执行文件提供参数。我把它留给读者作为练习;-)关于linux - 为什么用fork()和exec()创建的进程的pid最终改变了,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52062862/