扫码加入

  • 正文
  • 相关推荐
申请入驻 产业图谱

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

04/02 15:42
196
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

fork()会创建一个新的子进程,该子进程是调用进程(父进程)的一个副本。新的进程与原进程共享相同的代码,但它们拥有独立的地址空间和资源。

1.头文件

#include <sys/types.h>

#include <unistd.h>

2.函数原型

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 child's 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 child's 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() 的返回值是子进程的进程 ID(PID);在子进程中,fork() 返回 0;如果 fork() 调用失败,返回值是小于 0 的错误码。

⚫fork()函数具有并发执行:父进程和子进程几乎同时执行,输出的顺序无法保证。独立进程空间:父子进程共享代码段,但有各自独立的数据段、堆和栈,它们可以修改自己的数据,而不会影响彼此。写时拷贝:子进程只有在修改数据时,才会真正进行内存复制,从而减少不必要的资源消耗。通过这些特性,fork() 成为 Linux 系统中进程创建的核心函数。

相关推荐