linux 中的fork和exec函数是进程相关的两个函数,最早在大二的操作系统课上了解到。今天要写个小东西偶尔用到就研究了一下。
1.fork
fork的功能是创建一个和进程完全一样的子进程。完全的意思是指子进程的堆和栈和父进程是完全相同的。在子进程创建完成时,子进程和父进程共享内存。但是一旦共享的内存区域要被写入时(不管是父进程要写还是子进程要写)这块区域就会从父进程的进程空间复制到子进程,然后再执行写入。这就是通常说的copy on write,目的很明显,就是要节省不必要的内存消耗 。
这一点在安卓的虚拟机孵化进程zygote被使用,zygote在开机时就把所有系统java类的字节码加载到内存,当一个app启动时zygote就fork一下然后fork的子进程去执行app。这样所有app可以调用系统class而整个系统的内存中只有一份系统类,可以很大程度的节省内存, 同时也加快了app的启动。
linux系统中的所有进程都是init进程fork出来的,查看的话可以发现他的pid是1, 是系统内所有进程的父进程(或者祖先进程)。其实init也有个pid为0的父进程,开机完成后就不存在了,本文不涉及这方面。
fork包含在<unistd.h>头文件中, 其原型是:pid_t fork(void)
其中pid_t是进程pid的数据结构,可以被cast成int等类型,当frok成功时在父进程中的返回值是子进程的pid, 子进程中是0, 若没能创建子进程则返回负值。
写个小程序看看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
编译运行看看
1 2 3 4 5 6 |
|
getpid()返回当前进程的pid,getppid()返回父进程的pid。
这里在fork之后通过返回值知道自己是父进程还是子进程,然后通过if判断进行流程控制,父、子进程各自执行自己的任务。
2.exec系列函数
刚才说道linux系统内所有进程都是init进程的子孙进程,但是可能会让人不解:“这样的话所有进程不都是一样的吗”。这里我们要用到exec系列函数了。
exec系列函数在执行时会首先清空当前进程(调用exec函数的进程)的栈和堆等内存空间。然后创建新的空间。但是进程的pid和父进程等信息不会变。
exec系列函数有一下几个:
1 2 3 4 5 6 |
|