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\n", 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!='\n')
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.\n", num);
alarm(2);
}
int main()
{
signal(SIGALRM, sig_handler);<br>
alarm(2);<br>
while(1){
pause();
printf("pause is over.\n");
}
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\n",s);
execvp( command[0], command );
//perror( command );
exit( errno );
}
else {
//printf("%d\n",s);
wait ( &rtn );
printf( " child process return %d\n", rtn );
}
}
- 后续修改
参考教材第八章parseline等关于输入字符串的代码,问题得到了解决。
注:show为 2进制可执行文件,所以显示乱码。
参考资料
深入浅出---unix多进程编程之wait()和waitpid()函数
Sleep函数的真正用意
getenv putenv setenv和unsetenv详解
mybash的编写与调试的更多相关文章
- OC编写使用调试器
OC编写使用调试器 编写代码免不了,Bug.那么Debug就是程序员的必备技能了.本文和大家一起探讨,如何在应用开发编写代码过程中,使用日志项消息:以及使用动作.条件.迭代控制增强断点. 记录信息 在 ...
- MEX文件编写和调试
作者kaien,2010/02/16 以前我写过一篇文章,详细的介绍过MEX的格式,语法,编译,调试等.可惜记不清放在哪里了.而最近又用到MEX编程,所以只能重新温习一番.时间有限,只记下简要流程和注 ...
- VsCode编写和调试.NET Core
本文转自:https://www.cnblogs.com/Leo_wl/p/6732242.html 阅读目录 使用VsCode编写和调试.NET Core项目 回到目录 使用VsCode编写和调试. ...
- 如何快速编写和调试 Emit 生成 IL 的代码
.NET Core/.NET Framework 的 System.Reflection.Emit 命名空间为我们提供了动态生成 IL 代码的能力.利用这项能力,我们能够在运行时生成一段代码/一个方法 ...
- 一个项目的Makefile编写及调试
父Makefile 在src目录下包含很多文件夹,那么需要遍历所有的目录执行Makefile,那么给一个在src目录下的Makefile. # 需要排除的目录 exclude_dirs := incl ...
- 使用PyCharm实现远程编写并调试代码
使用PyCharm实现远程编写并调试代码 版权声明:本文为博主原创文章,转载请注明出https://www.cnblogs.com/wenqiangit/p/9771947.html 因为工作中使用的 ...
- Ubuntu\Linux 下编写及调试C\C++
一.在Ubuntu\Linux 下编写及调试C\C++需要配置基本的环境,即配置gcc编译器.安装vim编译器,具体配置安装步骤我在这里就不多说了. 二.基本环境配置完了我们就可以进入自己的程序编写了 ...
- 使用VsCode编写和调试.NET Core项目
本来我还想介绍以下VSCode或者donet core,但是发现都是废话,没有必要,大家如果对这个不了解可以直接google这两个关键字,或者也根本不会看我这边文章. 好直接进入主题了,本文的 ...
- Spark程序开发-环境搭建-程序编写-Debug调试-项目提交
1,使用IDEA软件进行开发. 在idea中新建scala project, File-->New-->Project.选择Scala-->Scala 2,在编辑窗口中完成Word ...
随机推荐
- Debian 静态网络配置
allow-hotplug enp6s0 iface enp6s0 inet static address gateway 192.168.2.1 # dns-* options are implem ...
- Django中模型(一)
Django中模型(一) 一. 基本开发流程 1. 配置数据库 2. 定义模型类:一个模型类都在数据库中对应一张数据表 3. 生成迁移文件 4. ...
- ZooKeeper学习之路 (四)ZooKeeper开发环境eclipse配置
一.eclipse中配置zookeeper开发环境 1)将zookeeper eclipse plugin中的6个jar包放到eclipse安装目录下的plugins文件中,重启eclipse (2) ...
- 分享一个ASP.NET的弹出层,比较好用!
网上的一些弹出层的控件多了去了,我很久之前用了一个,效果还不错,但如果应用到ASP.NET的话,会出现“弹出层内的控件runat='server'失效”的情况,具体情况我也不太会描述,但就是那些onc ...
- UVA - 11987 Almost Union-Find(带删除的并查集)
I hope you know the beautiful Union-Find structure. In this problem, you’re to implement something s ...
- Laravel发送邮件配置-问题解决
MAIL_DRIVER=smtp MAIL_HOST=smtp..com MAIL_PORT= MAIL_USERNAME=phpfangzhan@@@@@.com MAIL_PASSWORD=*** ...
- JAVA类加载和初始化
JAVA类的加载和初始化 一.类的加载和初始化过程 JVM将类的加载分为3个步骤: 1.加载(Load):class文件创建Class对象. 2.链接(Link) 3.初始化(Initialize) ...
- Oracle结合Mybatis实现取表TOP 10
之前一直使用mysql和informix数据库,查表中前10条数据十分简单: 最原始版本: select top * from student 当然,我们还可以写的复杂一点,比如外加一些查询条件? 比 ...
- Android系统架构(一)
一.Android系统版本简介 Android操作系统已占据了手机操作系统的大半壁江山,截至本文写作时,Android操作系统系统版本及其详细信息,已发生了变化,具体信息见下表,当然也可以访问http ...
- CentOS 7.0 防火墙操作
CentOS 7.0默认使用的是firewall作为防火墙,之前版本是使用iptables.所以在CentOS 7执行下面命令是无法查看防火墙状态的. [root@localhost ~]# serv ...