fork函数,对于子进程来说
1.复制问题
它会完完全全复制父进程的代码段,数据段,堆栈段等,子进程与父进程虽然虚拟地址不同,但是二者完全使用同一块物理空间。一般来说,代码段是不会变化的,但,是如果数据段或其他发生变化时,系统会为这个进程分配出一块新的物理空间,所以,另一个进程的数据不会受到影响,这个也叫做写时复用。(如果两个进程,没有一个进程打算改变数据段,堆栈段等,那么二者就会一直使用同一块物理空间,但是一旦一个进程想要发生改变,那么会获得一块新的物理空间)。
2.执行问题
子进程不仅仅复制上面那些,而且还会将程序计数器中的内容复制过来,所以,子进程实际上是从fork()之后才执行的,fork()之前的代码段是不执行的,但是父进程已经执行完的结果放在数据段是被子进程直接拿来用的。
例子:
1.
include <sys/ioctl.h>
char buf[128]="i am user................";
char buf1[128];
char buf2[128];
int main(int argc, const char *argv[])
{
int fd;
pid_t pid,pid1;
fd = open("hello",O_RDWR);
if(fd == -1){
perror("open hello is fail\n");
return -1;
}
pid = fork();
if(pid < 0){
perror("fork error");
return -1;
}else if(pid == 0){
write(fd,buf,sizeof(buf));
}else{
sleep(1);
read(fd,buf1,sizeof(buf1));
printf("1111111 data = %s\n",buf1);
}
在父进程中已经执行了open函数了,在open调用sys_open函数的过程中,已经将fd中填充好file_operations方法了,也就是此时已经可以对fd这个文件进行读写操作了,因为它里面已经填充上方法了,而子进程虽然不能执行fork之前的内容,因为fork之后产生了子进程,虽然子进程将父进程的代码段数据段完全复制过来,但是,程序计数器的内容也完全复制过来,所以,从fork之后开始执行剩下的代码,但不是说子进程没有办法执行open函数就没办法执行read函数了,因为在父进程执行的过程中已经对这个fd填充好操作方法了,而这个fd放在数据段,这个文件的驱动程序中已经填充好操作方法了,子进程只要找到这个文件即可,就可以直接进行读写操作,而不用并且也不能再执行这个open函数。也就是说代码段是按照程序计数器中的内容向下执行,数据段是按照fork之前父进程留下的数据段中的内容进行的。
2.
#include<stdio.h>
#include<unistd.h>
int main(int argc, const char *argv[])
{
pid_t pid;
printf("hello\n");
int a=2;
int b=3;
int c=a+b;
pid=fork();
if(pid==-1)
{
perror("fork error\n");
}
else if(pid==0)
{
printf("子进程c=%d\n",c);
}
else
{
printf("父进程c=%d\n",c);
}
return 0;
}
这里如果hello那里不加上\n,那么缓冲区中的hello也会被子进程复制,那么子进程在运行时,也会输出这个hello,因为子进程还把这个缓冲区复制了,如果父进程缓冲区刷新,那么子进程复制的缓冲区中就没有hello,不会输出hello,因为子进程本身不执行fork之前的这段代码。