我使用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;
}
方法1的结果
方法2的结果
我感到非常困惑,因为我认为在孩子中,execv()的使用是无关紧要的。不会改变pid。
答案 0 :(得分:0)
@Barmar在这里似乎是正确的……内部崇高的文本在这里创建了一个(好吧……肯定有一个以上)孩子……最有可能使用fork()
。您可以从下面的clone
呼叫中看出,崇高精神正在创造孩子。
[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 +++
在这里我们可以看到问题所描述的pid。请注意,来自strace的child_tidptr
值:它与升华的实际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
,您会发现pid与您的期望一致:
[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,则外壳将简单地调用exec
函数家族之一,以将其自身替换为可执行文件...如果将外壳 附加至TTY,则,它将首先通过另一个fork
调用。
POSIX spec中有很多非常好的信息,但是可能需要花费一些阅读才能真正了解……而且,请检查POSIX OS的源代码并尝试了解过程管理的内容。确实有助于巩固理解。我是用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
的{{1}}解析为告诉您使用哪种方法,以及在哪里找到可执行文件/为可执行文件提供args。我把它留给读者作为练习;-)