Linux主要提供了fork,vfork,clone三种进程创建方法,在Linux源码中,这三个的执行过程是执行fork(),vfork(),clone()时,同过一个系统调用表映射到sys_fork(),sys_vfork(),sys_clone()
,然后三个函数中去调用do_fork()去做具体的创建进程工作,
获取进程
每个进程都有一个ID,系统调用getpid可以得到进程的ID,而getppid可以得到父进程的ID
下面对函数进行说明
getpid函数
表头文件 | #include<unsitd.h> ——#include<sys/types.h> |
---|---|
定义函数 | gid_getpid(void) |
函数说明 | getpid()用来执行目前进程的组识别码 |
返回值 | 返回组识别码 |
举例说明
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
printf("gid is %d\n",getpid) ;
return 0;
}
这是在我的虚拟机上运行的,不同的系统值可能不同,以下代码都是在我的系统下运行的
getppid函数
表头文件 | #include<unistd.h> |
---|---|
定义函数 | pid_getppid(void) |
函数说明 | getppid()是用来取得目前进程的父进程识别码 |
返回值 | 父进程的识别码 |
举例说明
#include<unistd.h>
#includde<stdio.h>
int main()
{
printf("parent pid = &d\n",getppid());
return 0;
}
启动进程
fork函数
fork()用来创建子进程
表头文件 | #include<sys/types.h>——#include<unistd.h> |
---|---|
定义函数 | pid_'fork(void) |
函数说明 | 用来创建新的进程 |
返回值 | 在父进程中返回子进程的进程号,在子进程中返回0.错误返回-1 |
举例说明
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
int main(void)
{
pid_t child;
child = fork();
if(child == -1)
{
printf("子进程创建不成功\n");
exit(1);
}
else if(child == 0)
{
printf("我是子进程\n");
exit(0);
}
return 0;
}
父进程和子进程并不是相互独立的,相反他们会共用一些东西,在创建一个进程时,子进程只是完全复制父进程的资源,复制出来的子进程有着自己的结构和ID,但却复制父进程的其他资源,例如父进程打开几个文件,那么子进程也有几个打开的文件,但是子进程的改变不会影响父进程,下面举例说明
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
#include<errno.h>
int main()
{
int a = 5;
int b = 2;
pid_t pid;
pid = fork();
if(pid == 0)
{
a = a - 4;
printf("我是子进程:我的ID是——%d,a——%d,b——%d\n",pid,a,b);
}
else if(pid < 0)
{
perror("fork\n");
}
else
{
printf("我是父进程:我的ID是——%d,a——%d,b——%d\n",pid,a,b);
}
return 0;
}
可见,子进程中将变量a的值改为1,而父进程中则保持不变
启动进程,vfork()函数
vfork()函数用于建立一个新的进程
表头文件 | #include<unistd.h> |
---|---|
定义函数 | pid_t vfork(void) |
函数说明 | vfork()会产生一个新的子进程,其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码,组代码,环境变量,已经打开的文件代码,工作目录和资源限制等等。Linux使用copy-on-write(COW)技术,只有当其中一进程试图修改欲复制的空间时才会做真正的复制动作,由于这些继承信息是复制来的,并非指相同的内存空间,因此子进程对这些变量的修改,父进程并不会同步 |
返回值 | 如果vfork()成功则在父进程会返回新建立的子进程代码(PID),而在新建立的子进程中则返回0,如果vfork失败则直接返回-1,失败的原因存在于errno中 |
错误代码 | EAGAIN:内存不足,ENOMEM:内存不足,无法配置核心所需的数据结构空间 |
实例
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int main()
{
if(vfork() == 0)
{
printf("我是子进程\n");
exit(0);
}
else
{
printf("我是父进程\n");
}
return 0;
}
vfork系统调用不同有fork,用vfork创建的子进程与父进程共享地址空间,也就是说子进程完全运行在父进程的地址空间上,如果这时子进程修改了某个变量,这将影响到父进程如果上面fork的例子改成vfork,则a,b的值一样
值得注意的是,用vfork()创建的子进程必须显示调用exit()来结束,否则子进程将不能结束