fork()
- 计算机程序设计中的分叉函数。返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。 fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
mybash 版本一#include#include #include 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(numargs0){ arglist[numargs]=NULL; execute(arglist); numargs=0; } } }
wait()
- wait(等待子进程中断或结束) 相关函数 waitpid,fork 表头文件
#include#include 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#include #include #include void sig_handler(int num){ printf("receive the signal %d.\n", num); alarm(2);} int main(){ signal(SIGALRM, sig_handler); alarm(2); 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#include #include #include #include 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进制可执行文件,所以显示乱码。