我们先尝试编写创建两个程序,来理解Linux创建新进程的过程:
1 #include <sys/systypes.h> 2 #include <unistd.h> 3 4 int main() 5 { 6 if (fork() == 0) { 7 print("Child process!\n"); 8 } else { 9 print("Parent process!\n"); 10 } 11 return 0; 12 }运行结果为:
Child process! Parent process!代码二
1 #include <sys/types.h> 2 #include <unistd.h> 3 #include <stdio.h> 4 5 int main() 6 { 7 execl("./hello_world", NULL, NULL); 8 printf("execl failed!"); 9 return 0; 10 }运行结果
Hello World!通过上面的对比,可以看错:fork实际上是复制了一个“自己”,在fork之后有两个自己在运行。子进程和父进程是依靠fork的返回值是否为0来决定执行流。返回值为0则是子进程。返回值不是0则是父进程。
execl则是将执行的内容完全替换掉。在execl之后,执行的完全是一个新的进程。就进程不复存在。
可以将fork看作是复制,而execl则是替换。
linux就是这样创建进程的:fork一个进程,在用execl加载新的执行程序,替换新建的进程的执行内容。比如ls:bash通过fork一个新的bash,再execl("ls")来创建一个ls进程。
想要详细定位fork和execl在内核中的实现需要了解linux系统调用的处理流程。我们以fork为例子。我们可以通过下面的代码调用fork:
#include <memory.h> #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main() { pid_t pid; // pid = fork(); asm volatile( "mov $0x2, %