目录
fork()方法原型
父子进程
父子进程的pid
物理地址和逻辑地址
写实拷贝
fork()方法原型
pid_t fork(void);
pid_t是int类型代表进程的pid号
Linux内核2.4.0定义:
typedef int __kernel_pid_t;
typedef __kernel_pid_t pid_t;
每一个进程的pid都是唯一的,同一个程序每次运行都会产生一个新进程,pid不一样但他们的名字是一样的。
父子进程
fork函数复制当前进程生成一个新进程,调用fork的为父进程,新生成的为子进程。fork在父子进程中都会有返回值:父进程中返回子进程的pid,子进程创建成功返回0,创建失败返回-1。
所有父进程的资源都拷贝给子进程(父进程定义的东西子进程都有),父子进程一起执行,子进程从fork()返回之后开始执行(所以不会无限执行)。
使用父子进程可以用同一套代码完成不同的事情
下面使用父子进程分别打印两个字符串
输出,父子进程并发执行
父子进程的pid
pid从1开始往大增长,父进程的pid要比子进程小。
getpid()可以得到自己的pid
getppid()可以得到父进程的pid
父子进程是相对的,子进程再用fork那它就是fork出来进程的父进程了
物理地址和逻辑地址
逻辑地址是指在应用程序角度看到的内存单元、存储单元、网络主机的地址。
物理地址是数据在存储器中的地址。每一个字节单元给以一个唯一的存储器地址。又叫实际地址或绝对地址。
在父进程和子进程中,同一个变量的输出的地址是相同的
但是它们使用的是不同的空间,可以看到它们存放不同的数值,这可以证明它们的物理地址不是相同的,只是逻辑地址相同。程序输出的都是逻辑地址(相对nul偏移量),物理地址是看不到的。
上面代码中n作为临时变量离起始位置偏移量很远:
每一个进程的逻辑地址都是由存放代码段(函数)、数据段(全局变量)、堆(new/malloc)、栈(临时变量)、内核的空间构成,并依次远离0x00000000位置。如下图:
这些空间不一定全部用完,这也是不同程序中输出变量的地址可能相同的原因。
写实拷贝
如果父子进程用的统一变量的值是一样的,则让它们使用同一物理空间,当父或子进程的变量更改了再给它们分不同空间,这样提高fork的效率。
当它们用同一空间时,会有一个变量记录用这个空间的进程数量,如果一个进程结束,引用计数-1,另一个可以继续用,不会将这个空间释放。