文件描述符-内存申请与管理-fork()与execl联合创建进程代码
导语
事虽难做则必成,路虽远行则将致.–荀子*修身
文章目录
- 1.写时拷贝复习
- 2.文件操作的系统调用-open,read,write,close
- 2.1如何创建一个可读可可写文件
- 2.2与文件操作有关的系统调用
- 2.3 父进程 先 打开一个文件,fork后子进程是否可以共享使用?
- 2.2自己动手写cp函数
- 3.从进程视角看堆区内存申请与释放的有关问题
- 3.1.1C语言当中的内存泄漏
- 3.1.2 当物理内存中有1G的空间时,通过malloc申请1G空间是否能够成功
- 3.1.3在物理内存只有2G的系统中,malloc能否申请2G空间?
- 3.1.4 malloc 与fork ,父进程堆区申请的空间复制后,子进程也会有一份,需要释放吗?
- 4.进程替换
- 4.1通过man exec查看替换函数
- 4.2通过ececl 将当前的进程替换为ls
- 4.3fork 和exec联合创建一个全新进程
- 4.3.1fork与execl联合创建进程代码
提高fork()的效率-修改时再复制
fork(),在复制父进制时,如果有修改页面时再进行复制,其它的时期进行共享,降低内存的占用率
写实拷贝并不复制整个进程的地址空间,而是让父进程和子进程共享一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。资源的复制只有在写入的时候才进行,在此之前,只是以只读方式共享。
2.文件操作的系统调用-open,read,write,close 2.1如何创建一个可读可可写文件//创建一个可读可写的a.tet 文件
#include2.2与文件操作有关的系统调用#include #include #include int main(){ int fd=open("a.tet",O_WRONLY | O_CREAT,0600);//err -1,success fd>=0 文件描述符,0600表示可读可写 if(fd==-1){ exit(-1); } write(fd,"hello",5); close(fd); exit(0);
//打开一个已经存在的文件 Pathname:将要打开文件的路径和名称 flag:打卡标志,如以只读或者只写的方式打开 int open(const char *pathname,int flags); int open(const char * pathname,int flags,mode_t mode);
权限标识
O_WRONLY 只写方式打开 O_RDONLY 只读方式打开 O_RDWR 读写方式打开 O_CREAT 文件不存在则创建 O_APPEND 文件末尾追加 O——TRUNC 清空文件,重新写入 mode:权限 如:0600 可读可写
返回值:文件描述符–参数介绍
ssize_t read(int fd,void *buf,size_t count);
fd 对应文件打开的描述符 buf 存放数据的空间 count 计划从文件中读取多少字节数据 返回值:实际读到的字节数
int close(int fd)
fd 为要关闭的文件描述符2.3 父进程 先 打开一个文件,fork后子进程是否可以共享使用?
浪可以共享
为什么可以❓
由于fork创建的子进程的PCB是拷贝父进程的,子进程中PCB的文件表指向打开文件的指针,只是拷贝了父进程PCB的值,所以父子进程会共享fork之前打开的所有文件描述符。
2.2自己动手写cp函数#include#include #include #include #include #include int main(){ //buff 存放数据的空间 char buff[256]={0}; int fdr=open("a.tet",O_RDONLY); assert(fdr!=-1); int fdw=open("newa.tet",O_WRONLY|O_CREAT,0600); assert(fdr!=-1); int n=0; //在这里一定要注意,先将读到的值返回给n如果n>0的时候那么就写数据 while((n=read(fdr,buff,256))>0){ write(fdw,buff,n); } close(fdr); close(fdw); exit(0); }
我们截图看下,现在a.tet文件中的内容
我们运行一下上述代码,我们来看下效果
我们再来看下newa.tet当中共的内容
3.从进程视角看堆区内存申请与释放的有关问题 3.1.1C语言当中的内存泄漏- 一直向堆区申请内存空间而没有释放时,就会造成内存泄漏
- 丢失了指向堆区申请的内存空间的指针-找不到释放地点-造成内存泄漏
不论是否释放和指针丢失-造成的内存泄漏,在程序运行结束之后,操作系统都会自动回收
3.1.2 当物理内存中有1G的空间时,通过malloc申请1G空间是否能够成功- 如果存在虚拟内存,且虚拟内存+物理内存的容量大于1G的时候其就可以申请成功
- 但没有虚拟内存,只有物理内存时,时无法申请成功的
不能够申请2G的内存空间,因为只有2G的内存空间,所以进程地址空间肯定是小于2G的,所以是无法申请成功的
与内存空间多大没有关系了,因为只有2G的空间,要再大也给不了
3.1.4 malloc 与fork ,父进程堆区申请的空间复制后,子进程也会有一份,需要释放吗?需要两次释放,因为当malloc申请内存空间之后,我的父进程用有一个指针指向了这块儿内存空间,子进程中也有要给指针,指向了这块儿内存空间,所以二者都需要进行对应的释放
int main(){
char *s=(char *)malloc(128);
assert(s!=NULL);
pid_t pid=fork();
assert(pid!=-1);
if(pid==0){
strcpy(s,"child");
}else{
strcpy(s,"parent");
}
printf("s=%sn",s);
free(s);
exit(0);
}
4.进程替换
exec系列替换过程:PCB使用之前的只是做略微调整,进程实体进行更换
4.1通过man exec查看替换函数4.2通过ececl 将当前的进程替换为ls
#include4.3fork 和exec联合创建一个全新进程#include #include #include #include int main(){ printf("execl pid=%dn",getpid()); printf("将当前进程替换为lsn"); //ececl 执行成功不返回,直接从新程序的主函数开始,只有失败才返回错误码 execl("/bin/ls","ls","-l",(char *)0); perror("execl error"); exit(0); }
我们先看文件中的内容
我们再来看下,我们 my_copy当中的内容-就是复制 a.tet当中的内容 到 newa.tet中
#include4.3.1fork与execl联合创建进程代码#include #include #include #include #include int main(){ //buff 存放数据的空间 char buff[256]={0}; int fdr=open("a.tet",O_RDONLY); assert(fdr!=-1); int fdw=open("newa.tet",O_WRONLY|O_CREAT,0600); assert(fdr!=-1); int n=0; //在这里一定要注意,先将读到的值返回给n如果n>0的时候那么就写数据 while((n=read(fdr,buff,256))>0){ write(fdw,buff,n); } close(fdr); close(fdw); exit(0); }
先复制一个进程来执行,
#include#include #include #include #include #include int main(int argc,char* argv[],char *envp[]){ printf("当前进程ID为: pid=%dn",getpid()); //printf("将当前进程替换为lsn"); //ececl 执行成功不返回,直接从新程序的主函数开始,只有失败才返回错误码 //execl("/bin/ls","ls","-l",(char *)0); //fork 一个子进程来进行文件的复制 pid_t pid=fork(); assert(pid!=-1); if(pid==0){ printf("子进程的当前ID=%dt 子进程的父进程ID=%d n",getpid(),getppid()); execl("./my_copy","my_copy",(char*)0); printf("nnn"); } else{ printf("将当前进程替换为lsn"); execl ("/bin/ls","ls","-k",(char*)0); } wait(NULL); printf("over"); exit(0); }



