栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

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

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

文件描述符-内存申请与管理-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联合创建进程代码

1.写时拷贝复习

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

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

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

2.文件操作的系统调用-open,read,write,close 2.1如何创建一个可读可可写文件

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

#include 
#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);

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之前打开的所有文件描述符。

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语言当中的内存泄漏
  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=%sn",s);
        free(s);
        exit(0);
}
4.进程替换

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

4.1通过man exec查看替换函数

 
4.2通过ececl 将当前的进程替换为ls 
#include 
#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);
}

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

我们先看文件中的内容

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

#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);

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

先复制一个进程来执行,

#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);
}  

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/913819.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号