作业:利用文件IO函数拷贝图片。要求父进程拷贝前半部分,子进程拷贝后半部分。
#include<myhead.h> #define N 128 char buf[N] = { 0 };//初始化容器 int main(int argc, char const *argv[]) { pid_t pid;//创建进程 int r_fd,w_fd,size,ret; char ch = '\0'; r_fd = open(argv[1], O_RDONLY);//以只读的形式从外部传文件名打开 if(r_fd <0)//判断打开是否成功 { ERR_MSG("open"); exit(-1); } w_fd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);//以写的形式打开从外部传文件名 if(w_fd < 0)//判断打开是否成功 { ERR_MSG("write"); exit(-1); } //获取文件总大小 size = lseek(r_fd, 0, SEEK_END); if(size < 0)//判断是否有内容 { ERR_MSG("lseek"); exit(-1); } lseek(w_fd, size-1, SEEK_SET);//从移动写文件的偏移量到文件第一位 if(write(w_fd, &ch, 1) < 0) { ERR_MSG("write"); exit(-1); } size /= 2;//获取文件的一半大小的内容 //关闭文件 close(r_fd); close(w_fd); //创建进程 pid = fork(); if(pid < 0)//创建失败 { ERR_MSG("fork"); exit(-1); } //子进程拷贝一半 else if(0 == pid)//子进程 { r_fd = open(argv[1], O_RDONLY);//以只读的形式从外部传文件名打开 if(r_fd < 0) { ERR_MSG("open");//判断打开是否成功 exit(-1); } w_fd = open(argv[2], O_WRONLY); if(w_fd < 0) { ERR_MSG("write"); exit(-1); } //从头拷贝一半 lseek(r_fd,size,SEEK_SET); lseek(w_fd,size,SEEK_SET); while((ret = read(r_fd, buf, N)) > 0)//判断读取文件是否有内容 { write(w_fd, buf, ret);//讲读取到的内容写到文件里 } close(r_fd); close(w_fd); } else { //父进程拷贝一半 r_fd = open(argv[1], O_RDONLY);//以只读的形式从外部传文件名打开 if(r_fd < 0) { ERR_MSG("open"); exit(-1); } w_fd = open(argv[2], O_WRONLY); if(w_fd < 0) { ERR_MSG("open"); exit(-1); } //拷贝后一半 while(size > 0) { if(size > N) { write(w_fd, buf, read(r_fd, buf, N)); size -= N; } else { write(w_fd, buf, read(r_fd, buf, size)); break; } } //关闭文件 close(r_fd); close(w_fd); } return 0; }
思维导图
进程的五态图
虚拟内存空间与物理内存空间的关系
映射关系。用户只能访问用户空间的虚拟地址
进程的内存分布
注意:
- 当父进程执行fork后,会创建一个子进程。子进程用户空间中的所有资源都是从父进程拷贝过来的。
子进程不会运行当前创建它的那个fork函数,以及fork函数以上的内容。原因如下:
PC寄存器:存储的是CPU当前要运行的指令位置。CPU通过PC寄存器存储的位置去进程中取对应位置的指令。
- 拷贝完毕的一瞬间,父子进程的用户空间分布完全一致。即子进程用户空间中的初始资源是从父进程拷贝过来的。
但由于父子进程用户空间相互独立,所以父子进程根据CPU的调度运行各自的代码,申请各自空间内的变量,互不干扰。
- 父子进程映射的物理地址,根据写时拷贝原理。
- 当父子进程均不修改物理地址空间中的内容是,此时父子进程映射的物理地址是一致的。
- 若其中一个进程要修改物理地址空间中的内容是,需要申请一块新的物理地址空间给子进程映射。