fork函数
fork函数是创建新进程的一种方式,虽然vfork函数也可以创建新进程,但在创建进程时还是调用了fork函数
一般情况下,一个函数最多有一个返回值,但是fork函数比较特殊,有两个返回值,即调用一次返回两次。成功调用fork函数后,当前进程实际上已经分裂成为两个进程,一个是原来的父进程,另一个是刚刚创建的子进程。父子进程在调用fork函数的地方分开,
fork函数有两个返回值,一个是父进程调用fork函数后的返回值,该返回值是刚刚创建的子进程的ID:另一个是子进程中fork函数的返回值,该返回值是0.fork函数返回两次的前提是进程创建成功,如果进程创建失败,返回-1。两次返回不同的值,子进程返回值为0,而父进程的返回值为新创建的子进程的ID,这样可以用返回值来区分父子进程。
子进程会得到什么?
子进程会得到父进程的所有代码数据
子进程执行顺序
1、fork之前的代码:尽管子进程复制了这段代码,但是子进程不会执行。
2、子进程调用fork时:返回值为0,注意0不是pid
调用成功后直接进入子进程的代码段
3、执行fork后的代码,fork函数是子进程的起点
该程序足以证明fork所做的事
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
//利用printf函数 ,挤压数据的特点
//两个printf证明了fork复制了内存,并且复制了完整的代码段
int main(void)
{
pid_t pid;
pid = getpid();
int ret;
//printf("开始执行"); 如果不带\n 会将开始执行存储在printf函数里,当再次执行printf时,遇到\n 或缓存区满会输出该句话
//printf("开始执行\n"); 带上\n 在子进程中,因为\n 让开始执行已经消失,而不是积压在printf函数里
ret = fork();
//printf("开始执行\n");
//两个printf的位置不同,结果不同
if(ret > 0)
{
printf("parent PID = %d\n",getpid());
printf("parent ret = %d\n",ret);
}
else
{
printf("child PID = %d\n",getpid());
printf("child ret = %d\n",ret);
}
printf("------------------\n");
printf("结束执行\n");
}
//子进程:
//1、fork前的代码:尽管子进程复制了这段代码,但是子进程不会执行,子进程只会从开始执行
//2、子进程调用fork时,返回值为0,注意0不是pid
// 进入if(ret == 0){ } 执行大括号里的内容
//3、执行fork后的代码
// fork函数是子进程的起点
//
那fork对于文件操作时,又做了些什么?
在对文件进行操作时,如果fork所处的位置不同,那么在进行操作时,情况会不同
在父子进程里,独立的打开同一文件时
父子进程会拥有各自的文件描述符,指向的是不同的文件表,因为拥有不同的文件表,所以他们拥有各自独立的文件读写位置,会出现相互覆盖的情况,若果不想相互覆盖,要加上O_APPEND
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(void)
{
int ret;
int fd;
ret = fork();
if(ret>0)
{
fd = open("file.txt",O_RDWR | O_CREAT);
write(fd,"helloasdasdasd\n",strlen("helloasdasdasd\n"));
}
else
{
fd = open("file.txt",O_RDWR | O_CREAT);
write(fd,"world\n",strlen("world\n"));
close(fd);
}
}
由于父子进程指向了不同的文件表,所以文件位移量是不同的,所以会出现覆盖的情况,如果不想出现覆盖情况需要加上O_APPEND
父子进程外打开文件,父子进程内对文件进行操作时
子进程会集成父进程已经打开的文件描述符,如果父进程的 3 描述符指向了某个文件,子进程所继承的文件描述符 3 也会指向这个文件,像这种继承的情况,父子进程两个不同的 “文件描述符” 指向的是相同的文件表
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(void)
{
int ret;
int fd;
fd = open("file.txt", O_RDWR | O_CREAT );
ret = fork();
if(ret>0)
{
write(fd,"helloasdasdasd\n",strlen("helloasdasdasd\n"));
}
else
{
write(fd,"world\n",strlen("world\n"));
close(fd);
}
}
由于共享的是相同的文件表,所以拥有相同的文件读写位置,不会出现覆盖的情况,即不需要加上O_APPEND
程序是怎么运行起来的?
1、窗口进程先fork出子进程空间
2、调用exec加载 ./a.out程序,并把命令行参数和环境变量表传递给新程序的main函数的形参