1.fork()函数
头文件:#include <sys/types.h> #include<unistd.h> 函数原型:pid_t fork(void) fork函数它有两个返回值,调用一次返回两次,成功调用返回两次,成功调用后fork后,当前进程已经分裂为两个进程,一个是原来的父进程,另一个是刚刚创建的子进程,父进程fork后返回刚刚创建的子进程的ID,另一个是子进程中,fork的返回值,返回0, 如果fork失败返回-1;但是,fork()之后是先运行子进程还是父进程呢,这取决于内核的调度算法;要注意的是,操作系统一般会让所有进程都享有同等的执行权.除非某进程的优先级比其它高;来看个例子;
#include <stdio.h> #include <sys/types.h> #include <unistd.h> int main(void) { pid_t pid; char *msg; int k; printf("Process Creation Study\n"); pid=fork(); switch(pid) { case 0: msg="Child process is running"; k=3; break; case -1: perror("Process creation failed\n"); break; default: msg="Parent process is running"; k=5; break; } while(k>0) { puts(msg); sleep(1); k--; } }
运行结果:
yang@liu:~/Linux C$ ./a.out Process Creation Study Parent process is running Child process is running Parent process is running Child process is running Parent process is running Child process is running Parent process is running Parent process is running
可以发现父进程和子进程交替执行,子进程输出3条消息,父进程输出5条消息,这是怎样交替执行的呢,当系统调用fork之后,创建了一个子进程,它复制了父进程的资源.然后执行父进程,当break后进入while循环输出"Parent process is running"然后sleep(1)k=4,这时父进程在等待中,把cup的控制权又交到子进程,子进程执行,当子进程输出"Child process is running",然后执行sleep(1),在子进程等待时,父进程等待结束,就又执行父进程,就这样一直交替执行,直到进程结束. fork创建进程失败返回-1;失败的原因一般是父进程拥有子进程的个数超过了规定的限制,此时errno值为EAGAIN,内存不足errno的值为ENOMEM; 子进程会继承父进程的很多属性,主要包括:用户ID,组ID,当前的工作目录,根目录,打开的文件,创建文件时使用的屏蔽字,信号屏蔽字,上下文环境,共享的存储段,资源限制等, 子进程和父进程也有一些不同: 1.子进程有它唯一的进程ID, 2.fork的返回值不同,父进程返回子进程的ID,子进程返回0. 3.父进程ID不同,子进程的父进程ID为创建它的父进程ID; 4.子进程共享父进程打开的文件描述符,但父进程队文件描述符的改变不会影响子进程中的文件描述符. 5.子进程不继承父进程设置的文件锁. 6.子进程不继承父进程设置的警告. 7.子进程的未决信号集被清空.
2.vfork()函数
- vfork和frok都是调用一次,返回两次;
- 使用fork创建一个子进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性,而使用vfork创建一个进程时,操作系统并不将父进程的地址空间完全复制到子进程, 用vfork创建的子进程共享父进程的地址空间,也就是说子进程完全运行在父进程的地址空间上,子进程对地址空间的任何数据的修改,同样为父进程所见.
- 用fork创建的一个子进程,哪个进程先运行取决于系统的调度算法,而 vfork一个子进程,保证子进程先运行,当它调用exec或exit后才执行父进程.看一个例子:
#include <stdlib.h> #include <sys/types.h> int globVar = 5; int main() { pid_t pid; int var = 1,i; printf("fork is different with vfork\n"); // pid = fork(); pid = vfork(); switch(pid) { case 0: i=3; while(i-->0) { printf("Child process is running\n"); globVar++; var++; sleep(1); } printf("Child's globVar=%d,var=%d\n",globVar,var); exit(0); case -1: perror("Process creation failed\n"); exit(0); default: i=5; while(i-->0) { printf("Parent process is running\n"); globVar++; var++; sleep(1); } printf("Parent's globVar=%d,var=%d\n",globVar,var); exit(0); } }
执行结果:
yang@liu:~/Linux C$ gcc diffork.c yang@liu:~/Linux C$ ./a.out fork is different with vfork Child process is running Child process is running Child process is running Child's globVar=8,var=4 Parent process is running Parent process is running Parent process is running Parent process is running Parent process is running Parent's globVar=13,var=9
从结果可以看出,先执行了子进程,子进程退出后,父进程才执行,全局变量globVar=5;局部变量var=1;执行子进程i=3; 执行完后globVar=8;var=4;然后执行父进程,从结果GlobVar=13,var=9.可以看出,它们共享地址空间; 现在,去掉fork()的注释,注释掉vfork()执行结果:
yang@liu:~/Linux C$ gcc diffork.c yang@liu:~/Linux C$ ./a.out fork is different with vfork Parent process is running Child process is running Parent process is running Child process is running Parent process is running Child process is running Parent process is running Child's globVar=8,var=4 Parent process is running Parent's globVar=10,var=6
从执行结果可以看出,子进程完全复制了父进程的地址空间,子进程与父进程独立执行;