目录
一、fork( )
fork()
是一个系统调用,用于创建一个新的进程,新进程称为子进程,而调用fork()
的进程称为父进程。在调用fork()
之后,操作系统会复制父进程的所有资源(包括内存、文件描述符等),然后将复制的资源分配给子进程。
具体来说,fork()
函数的原型为:
#include <unistd.h>
pid_t fork(void);
- 返回值:在父进程中,
fork()
返回新创建的子进程的进程ID(PID),在子进程中,返回0。如果出错,返回-1。 - 参数:
fork()
函数不接受任何参数。
下面是一个简单的例子,演示了fork()
函数的基本用法:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t pid;
pid = fork();
if (pid == -1) {
perror("fork error");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程执行的代码
printf("This is the child process, PID: %d\n", getpid());
exit(EXIT_SUCCESS); // 子进程退出
} else {
// 父进程执行的代码
printf("This is the parent process, child PID: %d\n", pid);
exit(EXIT_SUCCESS); // 父进程退出
}
return 0;
}
在这个例子中,调用fork()
创建了一个子进程。在子进程中,fork()
返回0,因此打印了子进程的PID,并且子进程执行了exit()
函数退出。在父进程中,fork()
返回子进程的PID,因此打印了子进程的PID,并且父进程也执行了exit()
函数退出。
运行结果如下 :
This is the parent process, child PID: [子进程的PID]
This is the child process, PID: 0
其中,[子进程的PID]
会被实际的子进程的PID值所替代。这是因为在父进程中,fork()
返回的是子进程的PID,而在子进程中,fork()
返回0。因此,父进程会打印出子进程的PID,而子进程会打印出自己的PID为0。
二、vfork( )
vfork()
是另一个创建新进程的系统调用,但与fork()
不同,vfork()
通常用于创建一个新进程,而不会复制父进程的地址空间。它与fork()
类似,但有一些重要的区别和限制。
vfork()
函数的原型如下:
#include <unistd.h>
pid_t vfork(void);
- 返回值:在父进程中,
vfork()
返回新创建的子进程的进程ID(PID),在子进程中,返回0。如果出错,返回-1。 - 参数:
vfork()
函数不接受任何参数。
以下是一个简单的示例,演示了vfork()
函数的基本用法:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t pid;
pid = vfork();
if (pid == -1) {
perror("vfork error");
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程执行的代码
printf("This is the child process, PID: %d\n", getpid());
_exit(EXIT_SUCCESS); // 子进程调用_exit()函数退出
} else {
// 父进程执行的代码
printf("This is the parent process, child PID: %d\n", pid);
// 父进程继续执行
}
return 0;
}
运行此程序会得到与fork()
类似的结果,但使用vfork()
时需要特别注意子进程在调用exec()
或exit()
之前不会对父进程的内存空间产生影响。
运行结果如下:
This is the child process, PID: 12345
This is the parent process, child PID: 12345
其中,12345
是实际子进程的PID值。这是因为在父进程中,vfork()
返回的是子进程的PID,而在子进程中,vfork()
返回0。因此,父进程会打印出子进程的PID,而子进程会打印出自己的PID。
三、 fork( )和vfork( )的区别
fork()
和vfork()
都是用于创建新进程的系统调用,但它们之间有一些重要的区别:
地址空间:
fork()
会创建一个新的子进程,并复制父进程的地址空间到子进程中。子进程会有自己独立的地址空间,对地址空间的修改不会影响到父进程。vfork()
创建的子进程会共享父进程的地址空间。子进程在调用exec()
或exit()
之前,必须立即执行一个新的程序或者退出,以避免对父进程地址空间的修改。
性能:
vfork()
比fork()
更高效,因为它不需要复制整个地址空间。vfork()
只是在父进程的地址空间上创建一个新的进程,直到子进程调用exec()
或exit()
之后才会复制地址空间。这使得vfork()
更适合于创建子进程并立即执行一个新程序的情况。
父子进程的行为:
- 在
fork()
中,父进程和子进程的执行是独立的,它们各自拥有自己的地址空间和资源。子进程可以修改它自己的地址空间,而不会影响父进程。- 在
vfork()
中,子进程会共享父进程的地址空间,因此在调用exec()
或exit()
之前,子进程不能修改任何共享的内存数据。此外,在子进程调用exec()
或exit()
之前,父进程会阻塞,直到子进程调用这些函数。
返回值:
fork()
在父进程中返回新创建的子进程的PID,在子进程中返回0。vfork()
在父进程中返回新创建的子进程的PID,在子进程中也返回0。
四、 fork( )和vfork( )的使用时机
fork()
和vfork()
的使用时机取决于你的需求和情况。以下是一些适合使用每种方法的情况:
适合使用 fork()
的情况:
- 当父进程和子进程需要在执行期间共享一些数据,但是又需要在某些情况下独立运行时,可以使用
fork()
。因为fork()
会复制父进程的地址空间,所以父进程和子进程各自拥有独立的内存空间,可以互不影响地进行修改。- 当需要创建子进程执行一些并行任务,并且这些任务不会立即执行新的程序或者退出时,可以使用
fork()
。因为fork()
创建的子进程在创建后会立即复制父进程的地址空间,所以可以在创建后独立运行。
适合使用 vfork()
的情况:
- 当子进程需要立即执行一个新的程序,而且不需要对父进程的地址空间进行修改时,可以使用
vfork()
。因为vfork()
会共享父进程的地址空间,所以子进程可以直接在父进程的地址空间中执行新的程序,而不需要等到复制地址空间后再执行。- 当需要创建子进程来执行一个新的程序,但是不希望额外的内存复制开销时,可以使用
vfork()
。因为vfork()
不会立即复制父进程的地址空间,所以可以减少额外的内存开销,提高性能。
总的来说,如果需要创建一个新的子进程来执行一个新的程序,并且这个新程序会立即执行,那么vfork()
是一个更好的选择。但是如果子进程需要修改父进程的地址空间,或者需要在创建后独立运行一段时间,那么fork()
可能更适合。
做大做强,再创辉煌!