飞凌嵌入式ElfBoard-进程的基本操作之创建执行进程fork

张开发
2026/5/4 21:28:38 15 分钟阅读
飞凌嵌入式ElfBoard-进程的基本操作之创建执行进程fork
fork()会创建一个新的子进程该子进程是调用进程父进程的一个副本。新的进程与原进程共享相同的代码但它们拥有独立的地址空间和资源。1.头文件#include sys/types.h#include unistd.h2.函数原型pid_t fork(void);3.参数无。4.返回值成功创建子进程在父进程中返回子进程的 PID进程 ID在子进程中返回 0。创建进程失败返回值小于 0表示错误通常由于系统资源不足或达到进程限制。5.示例使用fork()函数创建子进程#include stdio.h#include stdlib.h#include sys/types.h#include unistd.h // 包含 fork() 和 getpid() 函数#include sys/wait.h // 包含 wait() 函数int main() {// 创建子进程pid_t pid fork();if (pid 0) {// 创建进程失败perror(fork failed);exit(EXIT_FAILURE);} else if (pid 0) {// 子进程代码printf(I am the child process. My PID is %d.\n, getpid());exit(EXIT_SUCCESS); // 子进程正常退出} else {// 父进程代码printf(I am the parent process. My PID is %d, and my childs PID is %d.\n, getpid(), pid);// 等待子进程结束wait(NULL);printf(Child process has terminated.\n);}return 0;}6.运行结果I am the parent process. My PID is 200737, and my childs PID is 200738.I am the child process. My PID is 200738.Child process has terminated.7.代码解析pid_t pid fork(); 创建一个新的子进程这个子进程是父进程的副本通过判断fock的返回值在父子进程中分别执行不同的代码。使用 wait() 函数可以确保父进程在子进程结束后继续执行以避免资源泄漏wait() 函数具体情况后面再做讲解。8.fork的父子进程之间的资源继承情况⚫共享代码段代码段文本段是只读的因此父进程和子进程可以共享同一个代码段。在内存中代码段只存在一份这样可以减少内存的浪费。父进程和子进程虽然执行相同的代码但它们运行在不同的进程空间中并拥有各自的上下文和数据。⚫复制数据段、堆、栈在 fork() 调用后数据段、堆和栈部分的内容是完全复制的。尽管初始时子进程是父进程的副本但它们的存储空间是独立的。这意味着子进程可以独立地修改它的数据段全局和静态变量、堆动态分配内存和栈局部变量和函数调用堆栈而不会影响父进程的相应部分反之亦然。⚫文件描述符的继承子进程会继承父进程的文件描述符表这意味着在子进程中打开的文件、管道、网络连接等都会继承下来。然而父进程和子进程在文件描述符上操作时它们的文件偏移量是共享的除非在 fork() 之后关闭或重新打开但对于每个进程的文件描述符表来说文件描述符的使用是独立的。⚫内存共享与分离写时拷贝Copy-on-Write, CoW为了提高效率现代操作系统实现了写时拷贝技术。当 fork() 被调用时子进程并不会立即复制整个父进程的数据段、堆和栈而是与父进程共享相同的内存页。只有当父进程或子进程尝试修改这些内存页时操作系统才会进行实际的内存拷贝创建独立的副本。这样可以显著节省资源特别是在子进程没有对内存进行修改的情况下。⚫fork()之后的执行父进程和子进程会并发地执行 fork() 调用之后的代码两者的执行顺序无法预测。可以通过 fork() 的返回值来区分父进程和子进程在父进程中fork() 的返回值是子进程的进程 IDPID在子进程中fork() 返回 0如果 fork() 调用失败返回值是小于 0 的错误码。⚫fork()函数具有并发执行父进程和子进程几乎同时执行输出的顺序无法保证。独立进程空间父子进程共享代码段但有各自独立的数据段、堆和栈它们可以修改自己的数据而不会影响彼此。写时拷贝子进程只有在修改数据时才会真正进行内存复制从而减少不必要的资源消耗。通过这些特性fork() 成为 Linux 系统中进程创建的核心函数。

更多文章