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详解

原文地址:https://www.cnblogs.com/xhwh/p/7711090.html