目录
1.fork函数
一个进程,包括代码,数据和分配给进程的资源。
fork函数通过系统调用。创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的 事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。
然后把原来的进 程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
包含的头文件:
#include<sys/types.h>
#include<unistd.h>
函数原型:
pid_t fork(void);
两个返回值:
=0:当前进程为子进程
>0:当前进程为父进程
‐1,出错
用户数据一样,但是进程ID不一致。
2.getpid/getppid函数
getpid():得到当前进程的PID
getppid():得到当前进程的父进程的PID
这两个函数通常用于调试、日志记录、进程管理或任何需要明确区分不同进程的场景。
3.父进程与子进程
父进程和子进程的一些关键点:
-
创建子进程:
- 父进程通过调用
fork()
创建子进程。 fork()
被调用一次,但会返回两次:在父进程中返回子进程的PID,在子进程中返回0。
- 父进程通过调用
-
PID和PPID:
- 每个进程都有一个PID,子进程的PID与父进程不同。
- 父进程的PID被称为PPID(Parent Process ID),子进程的PPID等于父进程的PID。
-
资源继承:
- 子进程继承了父进程的大部分资源,包括:
- 代码段(文本段)
- 数据段(全局变量和堆)
- 堆栈
- 文件描述符
- 环境变量
- 信号处理设置
- 子进程继承了父进程的大部分资源,包括:
-
独立性:
- 子进程有自己的地址空间,但一开始它是父进程的副本。
- 子进程可以独立于父进程运行,它们可以执行不同的代码路径。
-
执行流程:
fork()
之后,父进程和子进程都有各自的执行流程。- 父进程继续执行
fork()
之后的代码。 - 子进程从
fork()
之后的代码开始执行。
这点可以在前面的程序中加以验证。
但她两的执行顺序是不一定的,
-
退出和终止:
- 子进程通常在完成特定任务后调用
exit()
退出。 - 父进程可以使用
wait()
或waitpid()
等待子进程结束,以防止子进程变成僵尸进程。
- 子进程通常在完成特定任务后调用
-
僵尸进程:
- 如果父进程没有调用
wait()
或waitpid()
来收集子进程的终止状态,子进程可能会变成僵尸进程。 - 僵尸进程是已经完成执行但尚未被父进程回收其资源的进程。
- 如果父进程没有调用
-
孤儿进程:
- 如果父进程在子进程之前退出,子进程将成为孤儿进程。
- 孤儿进程会被init进程(PID为1的进程)收养,init进程会调用
wait()
来回收孤儿进程的资源。
-
进程组和会话:
- 默认情况下,子进程和父进程在同一个进程组和会话中。
- 进程组和会话是Linux中用于作业控制的机制。
-
fork()
的用途:- 并发执行:创建多个进程以并行执行任务。
- 任务分派:将不同的任务分配给不同的进程。
- 创建守护进程:通过在子进程中调用
setsid()
创建守护进程。
fork()
是Linux中进程创建的基础,它允许程序创建新的进程来执行并行或独立的任务。
4.父进程与子进程的应用场景:
-
并行处理:
- 程序可以创建多个子进程来并行处理任务,例如,一个科学计算程序可能创建多个子进程来处理不同的数据集。
-
任务分派:
- 一个复杂的任务可以被分解成多个子任务,每个子任务由一个子进程执行。例如,一个编译器可能创建多个子进程来并行编译不同的源文件。
-
服务端并发:
- Web服务器和数据库服务器通常使用子进程来处理客户端的并发连接。每个连接可以在一个独立的子进程中处理,以隔离不同的客户端请求。
-
守护进程(Daemons):
- 守护进程是一种在后台运行的服务,它们通常由父进程创建并在后台执行,如cron、sshd、web服务器等。守护进程通常在系统启动时创建,并一直运行直到系统关闭。
-
进程隔离:
- 通过创建子进程,可以将不同的任务隔离开来,这样即使一个子进程崩溃,也不会影响到其他子进程或父进程。
-
信号处理:
- 父进程可以监控子进程的状态,如果子进程退出或被信号中断,父进程可以采取相应的措施。
-
管道和数据流:
- 父进程和子进程可以通过管道进行通信,例如,子进程可以生成数据,父进程可以消费这些数据。
-
测试和调试:
- 在开发阶段,可以通过创建子进程来测试程序的不同部分,子进程可以用于模拟不同的运行环境