zoukankan      html  css  js  c++  java
  • mybash的编写与调试

    fork()

    • 计算机程序设计中的分叉函数。返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。
      fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
    mybash 版本一
    
    #include <errno.h>
     #include <stdio.h>
     #include <stdlib.h>
     char command[256];
     void main()
     {
      int rtn; /*子进程的返回数值*/
      while(1) {
          
          printf( ">" );
          gets( command, 256, stdin );
          command[strlen(command)-1] = 0;
          if ( fork() == 0 ) {
             execlp( command, NULL );
             
             perror( command );
             exit( errno );
          }
          else {
             wait ( &rtn );
             printf( " child process return %d
    ", rtn );
          }
      }
    }
    

    这个版本不能得到正确结果,会打印错误提示 ,但是可以根据运行结果的内容发现,fork()的返回值有两个,一个是0代表生成的子程序,还有一个代表的父程序。

    exec( )函数族

    • 在Linux中要使用exec函数族。系统调用execve()对当前进程进行替换,替换者为一个指定的程序,其参数包括文件名(filename)、参数列表(argv)以及环境变量(envp)。exec函数族当然不止一个,但它们大致相同,在 Linux中,它们分别是:execl,execlp,execle,execv,execve和execvp,可以通过manexec命令来了解它们的具体情况。
    • 在这个函数族的函数使用的过程中主要是注意字符串数组的存放,目前看来所有的程序问题主要集中在这一部分,在这里先贴一个在网上查到的输入代码,之后再仔细研究
     numargs=0;
      while(numargs<MAXARGS){
       printf("Arg[%d]?",numargs);
       if(fgets(argbuf,ARGLEN,stdin)&&*argbuf!='
    ')
         arglist[numargs++]=makestring(argbuf);
       else{
        if(numargs>0){
          arglist[numargs]=NULL;
          execute(arglist);
          numargs=0;
        }
       }
      }
    

    wait()

    • wait(等待子进程中断或结束)
      相关函数 waitpid,fork
      表头文件
    #include<sys/types.h> 
    #include<sys/wait.h>
    pid_t wait (int * status);
    
    • 函数说明

    wait()会暂时停止目前进程的执行,直到有信号来到或子进程结
    束。如果在调用wait()时子进程已经结束,则wait()会立即返
    回子进程结束状态值。子进程的结束状态值会由参数status 返回,
    而子进程的进程识别码也会一快返回。如果不在意结束状态值,则
    参数status 可以设成NULL。子进程的结束状态值请参考waitpid()。
    返回值
    如果执行成功则返回子进程识别码(PID),如果有错误发生则返回
    -1。失败原因存于errno 中。

    waitpid()

    waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。waitpid的返回值比wait稍微复杂一些,一共有3种情况:

    1.当正常返回的时候,waitpid返回收集到的子进程的进程ID;
    2.如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
    3.如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;
    当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD;
    

    exit

    • exit()通常是用在子程序中用来终结程序用的,使用后程序自动结束,跳回操作系统。
    • exit(0) 表示程序正常退出,exit⑴/exit(-1)表示程序异常退出。
    (1)exit和return 的区别: 
    
    a.exit是一个函数,有参数。exit执行完后把控制权交给系统 
    
    b.return是函数执行完后的返回。renturn执行完后把控制权交给调用函数。 
    
    (2)exit和abort的区别: 
    
    a.exit是正常终止进程 
    
    b.about是异常终止。 
    

    getpid()

    getpid是一种函数,功能是取得进程识别码,许多程序利用取到的此值来建立临时文件,以避免临时文件相同带来的问题。通过在虚拟机中运行可以看出,getpid()的返回值每次都不一样。

    getppid()

    getpid返回当前进程标识,getppid返回父进程标识。

    sleep()

    函数功能: 执行挂起一段时间;
    Sleep函数的一般形式:

    Sleep(unsigned long);//参数即为挂起时间
    

    pause()

    alarm(time);执行之后告诉内核,让内核在time秒时间之后向该进程发送一个定时信号,然后该进程捕获该信号并处理;
    pause()函数使该进程暂停让出CPU,但是该函数的暂停和前面的那个sleep函数的睡眠都是可被中断的睡眠,也就是说收到了中断信号之后再
    重新执行该进程的时候就直接执行pause()和sleep()函数之后的语句;
    可以用alarm()函数中断pause();

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
     
    void sig_handler(int num)
    {
        printf("receive the signal %d.
    ", num);
        alarm(2);
    }
     
    int main()
    {
        signal(SIGALRM, sig_handler);<br>
        alarm(2);<br>
        while(1){
            pause();
            printf("pause is over.
    ");
        }
        exit(0);
    }
    

    setenv

    函数说明 setenv()用来改变或增加环境变量的内容。参数name为环境变量名称字符串。参数 value则为变量内容,参数overwrite用来决定是否要改变已存在的环境变量。如果没有此环境变量则无论overwrite为何值均添加此环境变量。若环境变量存在,当overwrite不为0时,原内容会被改为参数value所指的变量内容;当overwrite为0时,则参数value会被忽略。返回值 执行成功则返回0,有错误发生时返回-1。

    unsetenv

    int unsetenv(const char *name);
    删除name的定义,即使不存在也不算出错。
    主要用于setenv()函数使用过后释放空间。

    • 伪代码

    int main(){
    
    //从终端读取要执行的命令
    //fork()产生子进程执行此命令
    //如果exec函数返回,表明没有正常执行命令,打印错误信息perro()
    //父进程, 等待子进程结束,并打印子进程的返回值wait(&rtn) 
    
    }
    
    • 产品代码

    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <limits.h>
    
    void main()
    {
    		
    	char *command[3];
    	command[0] = "ls";
    	command[1] = "-l";
    	command[2] = 0;
            
            int s,i=0;
            int rtn; 
            printf( ">" );
    	//printf("%s %s %s",command[1],command[2],command[3]);	
    	printf("%s",command[0]);
    	i=0;	
    	s=fork();
    	if ( s== 0 ) {
    	//printf("%d
    ",s);
    	execvp( command[0], command );
    	
    	//perror( command );
    	
    	exit( errno );
    	 }
    	 else {
    	
    	//printf("%d
    ",s);
    
    	wait ( &rtn );
    	
    	printf( " child process return %d
    ", rtn );
    	
    	}
    	
    	
    	}
    
    • 后续修改

    参考教材第八章parseline等关于输入字符串的代码,问题得到了解决。


    注:show为 2进制可执行文件,所以显示乱码。

    参考资料

    深入浅出---unix多进程编程之wait()和waitpid()函数
    Sleep函数的真正用意
    getenv putenv setenv和unsetenv详解

  • 相关阅读:
    vue 高度 动态更新计算 calcHeight watch $route
    vue 自定义组件 v-model双向绑定、 父子组件同步通信【转】
    vue 异步请求数据后,用v-if,显示组件,这样初始化的值就在开始的时候传进去了
    vue $parent 的上一级 有可能不是父组件,需要好几层$parent 如果这样 还不如用 this.$emit
    vue render {} 对象 说明文档
    params.row[params.column.key] vue h函数 当前单元格 h函数 div 属性 值或数组 render
    upload 上传按钮组件 iview
    下拉列表事件 Dropdown iview
    this.treeData = JSON.parse(JSON.stringify(this.d)) 树的序列化反序列化
    tree iview treeData json数据 添加 selected 数据 要进行vue.set 进行响应式添加
  • 原文地址:https://www.cnblogs.com/xhwh/p/7711090.html
Copyright © 2011-2022 走看看