UNIX环境高级编程的学习(二)

UNIX系统进程控制程序说明

该程序从标准输入读取命令,然后执行这些命令,程序涉及到的函数主要用法包括:

  • fgets的用法
  • execlp的用法
  • waitpid的用法
    程序如下:
#include "apue.h"
#include <sys/wait.h>
int main(void)
{
char buf[MAXLINE];
pid_t pid;
int status;
printf("%% ");
while(fgets(buf,MAXLINE,stdin)!=NULL){
	if(buf[strlen(buf)-1]=='\n')
	buf[strlen(buf)-1]=0;
	if((pid=fork())<0){
	err_sys("fork error");
	}else if(pid==0){   			/*child*/
	execlp(buf,buf,(char*)0);
	err_ret("couldn't execute:%s",buf);
	exit(127);
	}
/*parent*/
if((pid=waitpid(pid,&status,0))<0)
	err_sys("waitpid error");
printf("%% ");
}
exit(0);
}			


  • fgets的用法
    fgets(buf,MAXLINE,stdin);
    从标准输入中读取数据,每次读取一行,读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符,第bufsize个字符赋’\0’;如果文件中的字符不足bufsize-1个字符则读完该行结束,在这里MAXLINE应该是一个比较大的数,这样可以确保读完一行。
  • execlp的用法
    execlp(buf,buf,(char)0);*
    1.这个函数用来替换进程映像,在进程的创建上Unix采用了一个独特的方法,它将进程创建与加载一个新进程映象分离。这样的好处是有更多的余地对两种操作进行管理。 当我们创建了一个进程之后,通常将子进程替换成新的进程映象,这可以用exec系列的函数来进行。当然,exec系列的函数也可以将当前进程替换掉。 例如:在shell命令行执行ps命令,实际上是shell进程调用fork复制一个新的子进程,再利用exec系统调用将新产生的子进程完全替换成ps进程。
    2.实际上execlp()函数底层是通过execve系统调用实现:
#include <unistd.h>         
int execve(const char *filename, char *const argv[],char *const envp[]);  

DESCRIPTION:
execve() executes the program pointed to by filename. filename must be either a binary executable, or a script starting with a line of the form
第一个参数用来指定启动程序的名称包括路径名,如“/bin/pwd";
第二个参数用arg参数表示启动程序所带的参数,一般第一个参数为要执行命令名,不是带路径且arg必须以NULL结束
3.execlp()函数的特殊之处:
execlp第一个参数path不用输入完整路径,只有给出命令名即可,它会在环境变量PATH当中查找命令,也就是说可以不用再前面加斜线’/’;

  • waitpid的用法
    waitpid系统调用在Linux函数库中的原型是:
#include <sys/types.h> /* 提供类型pid_t的定义 */
#include <sys/wait.h>
pid_t waitpid(pid_t pid,int *status,int options) 

1.进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。
参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:pid = wait(NULL);如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。
2.pid:从参数的名字pid和类型pid_t中就可以看出,这里需要的是一个进程ID。pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
3.waitpid的返回值比wait稍微复杂一些,一共有3种情况:
1、当正常返回的时候,waitpid返回收集到的子进程的进程ID;
2、如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;
3、如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

综上:

首先打印一个提示符’%’,但是要写两个’%%‘才能输出一个’%‘;然后输入一个命令,接收到命令之后,创建一个子进程,子进程创建成功(即pid=0),通过ececlp函数,将子进程替换为刚刚接收到的输入命令,并执行该命令,输出执行后的结果,waitpid函数用于阻塞自己,及时销毁已经变成僵尸进程的子进程。

猜你喜欢

转载自blog.csdn.net/qq_40788950/article/details/80136139
今日推荐