我们都知道通过fork()系统调用我们可以创建一个和当前进程印象一样的新进程.我们通常将新进程称为子进程,而当前进程称为父进程.而子进程继承了父进程的整个地址空间,其中包括了进程上下文,堆栈地址,内存信息进程控制块(PCB)等.
1.父子进程
那么我们首先来先说说父进程和子进程之间的区别:
- 父进程设置了锁,子进程不继承
- 进程ID不同
- 子进程的未决告警被清除
- 子进程的未决信号集设置为空集
2.fork系统调用说明
通过man手册我们可以轻松知道fork()包含的头文件<sys/types.h>和<unistd.h>,功能就是创建一个子进程.函数原型:pid_t fork(void),pid_t是带一个代表经常号pid的数据结构.如果创建成功一个子进程,对于父进程来说是返回子进程的ID.而对于子进程来说就是返回0.而返回-1代表创建子进程失败.
#include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <errno.h> #include <signal.h> int main(void) { pid_t pid ; signal(SIGCHLD,SIG_IGN); printf("before fork pid:%d\n",getpid()); int abc = 10; pid = fork(); if(pid == -1) //错误返回 { perror("tile"); return -1; } if(pid > 0) //父进程空间 { abc++; printf("parent:pid:%d \n",getpid()); printf("abc:%d \n",abc); sleep(20); } else if(pid == 0){ //子进程空间 abc++; printf("child:%d,parent: %d\n",getpid(),getppid()); printf("abc:%d",abc); } printf("fork after...\n"); }before fork pid:27319parent:pid:27319
before fork pid:27319parent:pid:27319
abc:11
before fork pid:27319child:27320,parent: 27319
abc:11fork after...
3.fork()系统调用注意点:
通过以上程序我们可以知道:1)fork系统调用之后,父进程和子进程交替执行,并且它们处于不同空间中。
2)fork()函数的一次调用返回2次返回,这个有点抽象难理解,此时二个进程处于独立的空间,它们各自执行者自己的东西,不产生冲突,所以返回2次一次pid ==0,一次pid大于0.而至于是先子进程还是父进程先执行,这没有确切的规定,是随机的.
3)将fork()返回值大于零设置为父进程,这是因为子进程获得父进程的pid相对容易,而父进程获子进程pid叫难,所以在在fork()系统调用中将子进程的pid字节有它自己返回给父进程.
4)forl()的子执行过程在fork()之后并不是从头开始,因为在fork()之前,父进程已经为子进程搭建好了运行环境了.所以字节有效代码处开始.理解了上面四点,相信我们应该对此系统调用一定有较深的了解.
4.vfork()系统调用:
那么讲完了fork(),我们不妨和vfork()比较,并且学习终结一下vfork(.);vfork()在某些情况下,我们知道vfork()与fork()执行结果是一样的,除了子进程会执行一次exec系统调用或者调用_exit(0)退出.函数原型:pid_t vfork vfork(void),具体返回值与其中fork()类似. 这个函数时是在没有实现写时赋值前提下,所以现在我们并不推荐使用vfork().
- 结论如下 1)vfork() 子进程与父进程共享数据段
2)vfork() 中是子进程先执行,父进程后执行.
通常我们都是与exec函数在一起,在主进程中替换进程印象.