zoukankan      html  css  js  c++  java
  • 第五周 mybash的实现

    第五周 mybash的实现

    1. 使用fork,exec,wait实现mybash
    2. 写出伪代码,产品代码和测试代码
    3. 发表知识理解,实现过程和问题解决的博客(包含代码托管链接)
    

    1. fork() 函数:

    1. 一个进程,包括代码、数据和分配给进程的资源。
    2.  fork() 函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
    3. 一个进程调用fork() 函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
    
    在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。
    fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
    1)在父进程中,fork返回新创建子进程的进程ID;
    2)在子进程中,fork返回0;
    3)如果出现错误,fork返回一个负值;
    
    我们可以通过fork返回的值来判断当前进程是子进程还是父进程
    

    有如下代码:

    #include <unistd.h>  
    #include <stdio.h>  
    int main(void)  
    {  
       int i=0;  
       printf("i son/pa ppid pid  fpid/n");  
       //ppid指当前进程的父进程pid  
       //pid指当前进程的pid,  
       //fpid指fork返回给当前进程的值  
       for(i=0;i<2;i++){  
           pid_t fpid=fork();  
           if(fpid==0)  
               printf("%d child  %4d %4d %4d/n",i,getppid(),getpid(),fpid);  
           else  
               printf("%d parent %4d %4d %4d/n",i,getppid(),getpid(),fpid);  
       }  
       return 0;  
    }  
    

    运行结果如下:

    分析:
    第一次fork后,p3224(父进程)的变量为i=0,fpid=3225(fork函数在父进程中返向子进程id)p3225(子进程)的变量为i=0,fpid=0(fork函数在子进程中返回0)
    第二步创建了两个进程p3226,p3227,这两个进程执行完printf函数后就结束了,因为这两个进程无法进入第三次循环,无法fork,该执行return 0;了,其他进程也是如此。

    2. exec函数:

    1. fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。
    2. 它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。
    3. 这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。
    

    exec函数族使用注意点:
    在使用exec函数族时,一定要加上错误判断语句。因为exec很容易执行失败,其中最常见的原因有:
    ① 找不到文件或路径,此时errno被设置为ENOENT。
    ② 数组argv和envp忘记用NULL结束,此时errno被设置为EFAULT。
    ③ 没有对应可执行文件的运行权限,此时errno被设置为EACCES。

    在Linux中使用exec函数族主要有以下两种情况

    如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生。
    当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用任何exec 函数族让自己重生。
    

    execlp.c文件如下:

    #include <stdio.h>
    #include <unistd.h>
    int main()
    {
        if(fork()==0){
            if(execlp("/usr/bin/env","env",NULL)<0)
            {
                perror("execlp error!");
                return -1 ;
            }
        }
        return 0 ;
    }
    

    执行结果如图:

    由执行结果看出,execlp函数使执行码重生时继承了Shell进程的所有环境变量,其他三个不以e结尾的函数同理。

    3. wait()函数:

    1. wait()会暂时停止目前进程的执行, 直到有信号来到或子进程结束. 
    2. 如果在调用wait()时子进程已经结束, 则wait()会立即返回子进程结束状态值. 
    3. 子进程的结束状态值会由参数status 返回, 而子进程的进程识别码也会一快返回
    

    4使用fork,exec,wait实现mybash:

    部分代码展示,全部代码在码云里

    int main()
    {
        char cmdline[MAX];
        
        while(1){
            printf("bsetixx@besrixx-VirtualBox:~/XINAN/mybash/$ ");
            fgets(cmdline,MAX,stdin);
            if(feof(stdin))
            {
                printf("error");
                exit(0);
            }
            eval(cmdline);
        }
    }
    
    void eval(char *cmdline)
    {
        char *argv[MAX];
        char buf[MAX];
        int bg;
        pid_t pid;
        strcpy(buf,cmdline);
        bg = parseline(buf,argv);
        if(argv[0]==NULL)
            return;
        if(!builtin_command(argv)) 
        {   
        if((pid=fork()) == 0)
        {
            if(execvp(argv[0],argv) < 0) {
                printf("%s : Command not found.
    ",argv[0]);
                exit(0);
            }
        }
    
        if(!bg){
            int status;
            if(waitpid(-1,&status,0) < 0) 
                printf("waitfg: waitpid error!");
        }
        else
            printf("%d %s",pid, cmdline);
        return;
        }
    }
    
    

    代码提交截图

    代码提交连接

  • 相关阅读:
    电脑快捷键
    方法
    运算符和表达式
    Java关键字和标识符
    字体和文本
    盒子模型
    css
    常用标签
    第一次课(上)
    出现次数最多的数字
  • 原文地址:https://www.cnblogs.com/bestixx/p/7705185.html
Copyright © 2011-2022 走看看