文档介绍:Unix程序设计基础
轴
上一讲回顾
80386 CPU介绍
实模式与保护模式
特权级别
分段与分页
系统调用原理
软中断引起特权级别的切换
int 80h
被封装成一组C函数
上一讲回顾打开的文件描述字将被子进程继承。
进程创建
获得当前进程id: getpid
获得父进程id: getppid
函数原型:
#include <>
pid_t getpid(void);
pid_t getppid(void);
执行一个新程序
执行程序系统调用execve
函数原型:
#include <>
int execve(const char *path, const char *argv[],
const char *envp[]);
Unix还提供其它几个执行程序函数,execl,execlp,execle,execv,execvp都不是系统调用,依赖于execve。
执行一个新程序
path,执行的文件
argv,参数表
envp,环境变量表,一般直接用environ就行
如:
char *argv[] = {“gcc”, “-g”, “-c”, “”, NULL};
execve(“/usr/bin/gcc”, argv, environ);
执行一个新程序
execve启动一个新的程序,新的地址空间完全覆盖当前进程的地址空间,但当前进程把开的文件描述字(除非特别设置),当前工作目录等将被继承。
execve只返回负值表示调用失败,如果成功的话将永不返回。
shell执行程序的原理
敲入命令:
$ ps
shell进程到底做了什么事?
1、等待用户输入 (等待I/O,睡眠状态)
2、获得输入ps
3、fork();子进程把自己放到前台,并调用execve(“ps”, …);父进程把子进程放入前台,并等待子进程结束(父进程进入睡眠状态 )
4、子进程结束,父进程得到子进程的结束状态信息,并把自己放到前台,回到1。
shell执行程序的原理
由此可以看出,进程被创建的原因是因为fork被调用,而execve只是把当前进前的地址空间替换成新程序的地址空间。因此,不能说“进程是程序的一次执行”,“程序的执行”只是地址空间的替换。
思考: 在3中为什么既要父进程把子进程放到前台,又要子进程把自己放到前台?
有兴趣的话可以自己编写一个shell。
等待进程完成
子进程运行结束后(正常或异常),它并没有马上从系统的进程分配表中被删掉,而是进入僵死状态(Zombie),一直等到父进程来回收它的结束状态信息。
如果父进程没有回收走子进程的结束状态就已经退出,子进程将永远处于僵死状态;也有例外,如父进程先于子进程结束,子进程将被init进程继承,并回init进程回收其结束状态信息。
等待进程完成
回收子进程结束状态信息wait, waitpid
函数原型:
#include <sys/>
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid, int *stat_loc,
int options);
等待进程完成
当进程调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,WNOHANG, WUNTRACED或它们的按位或(”|”)。
WNOHANG表示不进入睡眠状态,即如果指定的子进程都还没有僵死掉,立即返回0。
WUNTRACED 我也不太清楚,不管它
多进程程序的一般结构
if ((pid = fork()) > 0)
{
parent’s code;
wait();
}
else if (pid == 0)
child’s code;
else
error handling;
return xxx;
信