Linux--文件描述-内存申请与管理-fork()与execl联合创建进程

文件描述符-内存申请与管理-fork()与execl联合创建进程代码


导语

事虽难做则必成,路虽远行则将致.–荀子*修身

在这里插入图片描述


1.写时拷贝复习

提高fork()的效率-修改时再复制

fork(),在复制父进制时,如果有修改页面时再进行复制,其它的时期进行共享,降低内存的占用率

写实拷贝并不复制整个进程的地址空间,而是让父进程和子进程共享一个拷贝。只有在需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。资源的复制只有在写入的时候才进行,在此之前,只是以只读方式共享。

2.文件操作的系统调用-open,read,write,close

2.1如何创建一个可读可可写文件

//创建一个可读可写的a.tet 文件

#include <stdio.h>
#include<fcntl.h>
#include<stdlib.h>
#include <unistd.h>
 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);

OW8EQ0.png

OW8JOK.png

2.2与文件操作有关的系统调用

//打开一个已经存在的文件 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之前打开的所有文件描述符。

OhwIje.png

2.2自己动手写cp函数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
/*将当前目录下的a.tet的普通文件复制一份,新文件名交newa.tet*/
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文件中的内容

Ohrev8.png

我们运行一下上述代码,我们来看下效果

OhrJ2V.png

我们再来看下newa.tet当中共的内容

OhrUrF.png

3.从进程视角看堆区内存申请与释放的有关问题

3.1.1C语言当中的内存泄漏

  1. 一直向堆区申请内存空间而没有释放时,就会造成内存泄漏
  2. 丢失了指向堆区申请的内存空间的指针-找不到释放地点-造成内存泄漏

💥不论是否释放和指针丢失-造成的内存泄漏,在程序运行结束之后,操作系统都会自动回收

3.1.2 当物理内存中有1G的空间时,通过malloc申请1G空间是否能够成功

  1. 如果存在虚拟内存,且虚拟内存+物理内存的容量大于1G的时候其就可以申请成功
  2. 但没有虚拟内存,只有物理内存时,时无法申请成功的

3.1.3在物理内存只有2G的系统中,malloc能否申请2G空间?

不能够申请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=%s\n",s);
        free(s);
        exit(0);
}

4.进程替换

exec系列替换过程:PCB使用之前的只是做略微调整,进程实体进行更换

4.1通过man exec查看替换函数

Ohz9ED.png

/*
参数解释
*panthname:新替换的主程序的路径名称
*agr:传给新程序主函数的第一个参数,一般为程序名字
*arg:后面是剩余的参数列表,参数个数可变
⭐最后一个参数必须为空指针
*/

4.2通过ececl 将当前的进程替换为ls

#include <stdio.h>
#include <stdlib.h> 
#include <unistd.h>
#include <assert.h> 
#include <string.h>
int main(){
        printf("execl pid=%d\n",getpid());
        printf("将当前进程替换为ls\n");
        //ececl 执行成功不返回,直接从新程序的主函数开始,只有失败才返回错误码
        execl("/bin/ls","ls","-l",(char *)0);
        perror("execl error");
        exit(0);
}

O4AvJf.png

4.3fork 和exec联合创建一个全新进程

我们先看文件中的内容

O4K7Vg.png

我们再来看下,我们 my_copy当中的内容-就是复制 a.tet当中的内容 到 newa.tet中

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <fcntl.h>
#include <unistd.h>
/*将当前目录下的a.tet的普通文件复制一份,新文件名交newa.tet*/
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);

}

4.3.1fork与execl联合创建进程代码

先复制一个进程来执行,

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <wait.h>
int main(int argc,char* argv[],char *envp[]){
        printf("当前进程ID为: pid=%d\n",getpid());
        //printf("将当前进程替换为ls\n");
        //ececl 执行成功不返回,直接从新程序的主函数开始,只有失败才返回错误码
        //execl("/bin/ls","ls","-l",(char *)0);
        //fork 一个子进程来进行文件的复制
        pid_t pid=fork();
        assert(pid!=-1);
        if(pid==0){

                printf("子进程的当前ID=%d\t 子进程的父进程ID=%d \n",getpid(),getppid());
                execl("./my_copy","my_copy",(char*)0);
                printf("\n\n\n"); 
        }
        else{
                printf("将当前进程替换为ls\n");
                execl ("/bin/ls","ls","-k",(char*)0);
        }
        wait(NULL); 
        printf("over");
        exit(0);
}  

O4QtpR.png

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HANWEN KE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值