linux实验五 信号应用,实验五(2) Linux 进程管理

实验五(2) Linux 进程管理

Linux 进程管理

1、实验目的

通过进程的创建、撤销和运行加深对进程概念和并发执行的理解,明确进程和程序之间的区别。

2、背景知识

在Linux 中创建子进程要使用fork()函数,执行新的命令要使用exec()系列函数,等待子进程结束使用wait()函数,结束终止进程使用exit()函数。fork()原型如下:pid_t fork(void);

fork 建立一个子进程,父进程继续运行,子进程在同样的位置执行同样的程序。对于父进程,fork()返回子进程的pid,对于子进程,fork()返回0。出错时返回-1。exec 系列有6 个函数,原型如下:

extern char **environ;

int execl( const char *path, const char *arg, ...);

int execlp( const char *file, const char *arg, ...);

int execle( const char *path, const char *arg , ..., char * const envp[]);

int execv( const char *path, char *const argv[]);

int execve (const char *filename, char *const argv [], char *const envp[]);

int execvp( const char *file, char *const argv[]);

exec 系列函数用新的进程映象置换当前的进程映象.这些函数的第一个参数是待执行程序的路径名(文件名). 这些函数调用成功后不会返回,其进程的正文(text),数据(data),bss和栈(stack)段被待执行程序程序覆盖。但是进程的PID 和所有打开的文件描述符没有改变,同时悬挂信号被清除,信号重置为缺省行为.

在函数execl,execlp,和execle 中, const char *arg 以及省略号代表的参数可被视为arg0,

arg1, ...,argn.他们合起来描述了指向NULL 结尾的字符串的指针列表,即执行程序的参数列表.作为约定,第一个arg 参数应该指向执行程序名自身,参数列表必须用NULL 指针结束.execv和execvp函数提供指向NULL结尾的字符串的指针数组作为新程序的参数列表.作为约定,指针数组中第一个元素应该指向执行程序名自身.指针数组必须用NULL 指针结束。

execle 函数同时说明了执行进程的环境(environment),他在NULL指针后面要求一个附加参数,NULL 指针用于结束参数列表,或者说,argv数组.这个附加参数是指向NULL结尾的字符串的指针数组,他必须用NULL 指针结束。其他函数从当前进程的environ 外部变量中获取新进程的环境.

execlp和execvp可根据path搜索合适的程序运行,其他则需要给出程序全路径。

execve()类似execv(),但是加上了环境的处理。

wait(), waitpid()可用来等待子进程结束。函数原型:

#include

pid_twait(int*stat_loc);

pid_twaitpid(pid_tpid,int*stat_loc,intoptions);

当进程调wait,它将进入睡眠状直到有一个子进程结束。wait函数返回子进程的进程id,stat_loc中返回子进程的退出状态。waitpid 的第一个参数pid 的意义:pid > 0: 等待进程id 为pid 的子进程。pid==0:等待与自己同组的任意子进程。

pid == -1: 等待任意一个子进程

pid < -1: 等待进程组号为-pid 的任意子进程。

因此,wait(&stat)等价于waitpid(-1, &stat, 0),waitpid第三个参数option可以是0,WNOHAN,WUNTRACED 或这几者的组合。

3、实验内容和步骤

(3)实现一个简单的shell(命令行解释器)

你的shell 类似于sh,bash,csh等,必须支持以下内部命令:

cd 更改当前的工作目录到另一个。如果未指定,输出当前工作目录。如果不存在,应当有适当的错误信息提示。这个命令应该也能改变PWD 的环境变量。environ 列出所有环境变量字符串的设置(类似于Unix 系统下的env 命令)。

echo 显示echo 后的内容且换行

help 简短概要的输出你的shell的使用方法和基本功能。

jobs 输出shell 当前的一系列子进程,必须提供子进程的命名和PID 号。

quit,exit,bye 退出shell。

4.实验源代码

#include

#include

#include

#include

#include

#include

#include

#include

#defineNUM1024

#defineSIZE50

intmystrtok(char*argv[],char*string);

//这个函数做的是对字符串的分割,把命令分割开,用到了字符串的分割函数

intmystrtok(char*argv[],char*string)

{

inti=0;

chardelim[]=" ";

char*p;

argv[0]=strtok(string,delim);//字符串分割函数的使用

//printf("%s\n",argv[0]);

while(argv[i]!=NULL)

{

argv[++i]=strtok(NULL,delim);

//printf("%s is %d\n",argv[i],i);

}

return0;

}

//获得一个命令提示符的字符串

char*getusername(charbuffer[NUM])

{

uid_tuserid;

char*username;

char*hostname;

char*ptr,*p;

charbuf1[1024],buf2[1024];

char*delim=".";

intid;

getwd(buf2);//这段代码说明的是对命令提示的路径获得

username=getenv("USER");//调用getenv函数,来获得shell命令的提示中的用户名

strcpy(buffer,username);

strcat(buffer,"@");

id=gethostname(buf1,sizeofbuf1);//调用此函数来获取shell命令的提示中的主机名

p=strtok(buf1,delim);//对主机进行截取

strcat(buffer,p);//字符串的连接函数

ptr=strrchr(buf2,'/');//字符串的从后往前进行截取的函数,讲多得shell命令提示中的路径

//比较字符串,判断用户的路径是在"/","~",还是其他当中

if(strcmp(ptr,"/")==0)

{

ptr="/";

}

elseif(strcmp(ptr,"~")==0)

{

ptr="~";

}

else

{

ptr=strtok(ptr,"/");

}

//把获得的 [用户名@主机名 路径]连接在一起

strcat(buffer," ");

strcat(buffer,ptr);

returnbuffer;

}

intmain()

{

pid_tpid;

intstatus;

char*argv[NUM];

charbuffer[NUM];

charstr[NUM];

intj=-1;

char*string=NULL;

string=getenv("USER");

//当前用户是root用户还是普通用户,通过字符串的比较,如果是root,则返回0;

if((strcmp(string,"root"))==0)

{

j=0;

}

while(1){

//通过调用上面自定义的getusername()函数,来得到shell命令中的提示

printf("[%s]",getusername(buffer));

//判断是使用root的提示#,还是其他用户的$

if(j==0)

{

printf("# ");

}

else

{

printf("$ ");

}

//字符串的输入,要用gets函数或者用fgets函数,因为scanf函数把空格看成字符串的结束

gets(str);

//调用字符串的分割函数,获得要截取出来的命令和命令参数,例如:ls -a分别放到argv[0],argv[1]中

status=mystrtok(argv,str);

if(status!=0)

{

printf("fail to getargv!\n");

}

//通过fork()函数来创建一个父进程和一个子进程

pid=fork();

if(-1==pid)

{

printf("your fork failed!\n");

}

elseif(pid==0)

{

//子进程用来对shell命令进程进程解释执行的

if(argv[1]!=NULL)

{

execvp(argv[0],argv);

}

elseif(argv[1]==NULL)

{

execlp(argv[0],argv[0],NULL,NULL);

}

}

else

{

//父进程用来等待子进程的结束,然后再循环输入shell命令

if(wait(&status)==-1)

{

printf("wait failed!\n");

exit(1);

}

}

}

return0;

}

5.实验截图

实验截图如图5-1和5-2:

d5d45ae18e5a3ea7.png

图 5-1

010f25d8cf5526d5.png

图 5-2

6.实验总结

·了解Linux进程的创建

·了解子进程创建新任务的方法

·掌握了shell的编写

·对sehll的编写有了初步认识

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值