1 / 20

进程和程序

进程和程序. 程序 指令和数据的集合 存放在磁盘上的一个普通文件里 文件的 i 节点中标为可执行,内容符合系统要求 进程 包括指令段、用户数据段和系统数据段的执行环境 进程和程序的关系 程序用于 初始化 指令段和用户数据段 初始化后,进程和初始化它的程序之间无联系 进程运行时 , 它对应的磁盘上的程序文件不可修改 / 删除 几个同时运行的进程可以由同一程序初始化得到,进程之间没什么联系。核心通过安排这样的进程来共享指令段以节省内存 , 但这种安排对用户来说是透明的。. 进程的系统数据. 进程的系统数据 PCB

Download Presentation

进程和程序

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 进程和程序 • 程序 • 指令和数据的集合 • 存放在磁盘上的一个普通文件里 • 文件的i节点中标为可执行,内容符合系统要求 • 进程 • 包括指令段、用户数据段和系统数据段的执行环境 • 进程和程序的关系 • 程序用于初始化指令段和用户数据段 • 初始化后,进程和初始化它的程序之间无联系 • 进程运行时,它对应的磁盘上的程序文件不可修改/删除 • 几个同时运行的进程可以由同一程序初始化得到,进程之间没什么联系。核心通过安排这样的进程来共享指令段以节省内存,但这种安排对用户来说是透明的。

  2. 进程的系统数据 • 进程的系统数据PCB • 在UNIX内核中,含有进程的属性,包括: • 进程状态,优先级信息 • 核心堆栈 • 当前目录(记录了当前目录的i-节点),根目录 • 打开的文件描述符表 • umask值 • 进程PID,PPID • 进程主的实际UID/GID,有效UID/GID • 进程组组号

  3. user结构和proc结构 • user结构(约5000字节),<sys/user.h > • proc结构(约300字节),<sys/proc.h> • 进程运行时才需要的数据在user结构 • 其它信息存于proc结构 • 用户程序不能直接存取和修改进程的系统数据 • 系统调用可用来访问或修改这些属性 • 如: chdir, umask, open, close • setpgrp, getpid, getppid

  4. 进程的基本状态 • 基本状态 • 进程创建之后,主要有运行状态和睡眠状态(也叫阻塞状态,等待状态,挂起状态,等等)。 • 在核心中,将运行状态和睡眠状态的程序组织成不同的队列,系统总是在分时处理运行状态的进程,而不顾那些处于睡眠状态的进程。 • 处于睡眠状态的进程,在条件满足后,转化为运行状态,进入运行状态进程的队列而被调度。 • 进程在睡眠时,不占用CPU时间 • 注意:在编程时,程序不要处于忙等待状态

  5. 进程的调度 • 调度优先级 • UNIX核心,将可运行进程按优先级分成几个不同的队列,高优先级进程优先被调度执行。 • 可以用nice()系统调用调整进程的优先级 • 进程的优先级总在不停地发生变化 • 处于睡眠状态的进程一旦被叫醒后,被赋以高优先级,以保证人机会话操作和其它外设的响应速度。

  6. 系统调用 • UNIX中系统调用(system call)是UNIX内核与应用程序之间的唯一接口。 • 内核对外提供的所有的功能均以系统调用的方式出现,应用程序只有通过系统调用才能申请和访问硬件资源(内存和磁盘,I/O设备)和内核数据 • 进程不可直接读写I/O端口和接管硬件中断,必须要通过系统调用。 • 进程调用一次系统调用要导致CPU在用户态和核心态之间作一次切换,比在进程自己的地址空间中调用一个子例程要花费更长时间(所以UNIX中提供了文件缓冲I/0库程序) • C程序员在使用系统调用和使用其它函数调用时,用法上没什么区别

  7. 获取系统调用返回值 函数返回值 UNIX的大多系统调用都返回一个整数值,如: open(), wrire(), read()等, 当返回值为-1时,表示系统调用执行失败,系统会填写变量errno errno C程序库中定义的全局性整数,说明失败的原因, errno可能的取值在<sys/errno.h>文件中定义了宏,如: EBADF, EINTR, ENOMSG等等。 对于某一系统调用,直接用man命令查阅联机手册, 得知系统调用失败时errno可能的取值及原因 sys_errlist 还有一个sys_errlist表,也可以直接引用,是错误代码对应的错误信息表

  8. perror/strerror 与系统调用执行失败有关的的函数: char *strerror(int errnum); void perror (char *s); perror会在stderr上产生一条消息,描述在系统调用或使用库函数(库函数中发出了系统调用)期间所遇到的最后一个错误。先印出字符串s,再印出一个冒号和空格,然后再印出这条消息和换行符 strerror()根据错误号,得到一个描述这一错误的字符串. 举例程序 执行时,如果文件打开失败(系统调用open),就给出一条信息,根据失败的原因不同,打印出的错误信息内容也不同,如:没有访问权限,文件不存在,等等。

  9. 系统调用举例 #include <sys/fcntl.h> extern int errno; extern char *sys_errlist[]; void main(int argc, char **argv) { int fd; fd=open(argv[1],O_RDWR); if(fd==-1) { printf("errno=%d [%s]\n",errno, sys_errlist[errno]); printf("strerror=[%s]\n",strerror(errno)); perror("Open file"); } else { printf("OK\n"); /* do something here */ } } 执行结果 errno=21 [Is a directory] strerror=[Is a directory] Open file: Is a directory

  10. 系统调用fork • fork系统调用是创建新进程的唯一方式 • 继承:fork创建一个新进程,新进程的指令,用户数据段和系统数据段几乎都是旧进程的复制 • 父进程和子进程:原先的进程被称做“父进程”,新创建的进程被称作“子进程” • fork返回值:父子两进程都收到返回值,但不相同。返回值很关键,它用于区分父进程(返回值>0,是子进程的PID)和子进程(返回值=0)。fork调用唯一能出错的原因是资源耗尽(返回值=-1) • 内核在实现fork调用时,首先初始化创建一个新的proc结构,然后复制父进程环境(包括user结构和内存资源)给子进程 • 父子进程可以共享程序和数据(例如:copy-on-write技术),但是系统核心的这些安排,对程序员透明

  11. fork举例 执行结果 Hello pid=815 ppid=814,a=6 Bye Pid=814 child=815,a=6 Bye main() { int a,pid; printf("Hello\n"); a=3; pid=fork(); a+=3; if(pid>0) { printf("Pid=%d child=%d,a=%d\n", getpid(),pid,a); } else if(pid==0) { printf("pid=%d ppid=%d,a=%d\n", getpid(),getppid(),a); } else { perror("Create new process"); } printf("Bye\n"); }

  12. 命令ps 功能 查阅进程状态(process status)(实际上就是将内核中proc[]和user[]数组的内容有选择地打印出来) 选项 用于控制列表的行数(进程范围)和列数(每进程列出的属性内容) 无选项:只列出在当前终端上启动的进程。 列出的项目有:PID,TTY,TIME,COMMAND e选项:列出系统中所有的进程(进程范围) t选项:列出指定终端上的所有进程(进程范围) f选项:以full格式列出每一个进程(控制列的数目) l选项:以long格式列出每一个进程(控制列的数目)

  13. 命令ps举例 例:ps -ef命令的输出 UID PID PPID C STIME TTY TIME COMMAND root 0 0 0 16:11:14 ? 0:00 sched root 1 0 0 16:11:14 ? 0:01 /etc/init root 2 0 0 16:11:14 ? 0:00 vhand root 3 0 0 16:11:14 ? 0:00 bdflush root 6547 335 0 16:15:05 01 0:00 server 4 1 root 175 1 0 16:11:14 ? 0:00 inetd root 173 1 0 16:11:14 ? 0:00 syslogd root 296 1 0 16:11:21 ? 0:00 /tcb/files/no_luid/sdd root 6551 291 80 16:17:16 08 0:37 ifvl2 -trace4 root 335 1 0 16:11:31 01 0:00 server_ctl root 337 1 0 16:11:33 01 0:05 server_ap root 353 1 0 16:12:01 12 0:00 client_ctl 100.1.1.3 root 356 295 0 16:12:07 12 0:04 client_ap 1403 UID:用户ID(注册名), PID:进程ID PPID:父进程的PID, STIME:启动时间 TTY:终端的名字 , COMMAND:命令名 TIME:累计执行时间(占用CPU的时间)

  14. 访问环境参数的三种方法 main() { extern char **environ; char **p; p=environ; while(*p) printf(”[%s]\n”,*p++); } main(int argc, char **argv, char **env) { char **p; p=env; while(*p) printf(”[%s]\n”,*p++); } main() { char *p; p=getenv(”HOME”); if(p) printf (”[%s]\n”); }

  15. exec系统调用 用一个指定的程序文件,重新初始化一个进程。 exec可以指定新的命令行参数和环境参数 注意:exec并不创建新进程,只是将当前进程重新初始化了指令段和用户数据段,堆栈段,重新初始化CPU的PC指针 6种exec系统调用 execl / execv / execle execve / execlp / execvp exec前缀,后跟一至两个字母,这里字母代表含义为: l--list, v--vector, e--env, p--path l与v:指定命令行参数的两种方式,l以表的形式,v要事先组织成一个指针数组 e:需要指定envp来初始化进程。 p:使用PATH查寻可执行文件file

  16. exec系统调用(续) int execl(path,arg0,arg1,...,0); char *path,*arg0,*arg1,...,*argn; int execv(path,argv) char *path,**argv; int execle(path,arg0,arg1,...,argn,0,envp) char *path,*arg0,*arg1,...,*argn,**envp; int execve(path,argv,envp) char *path,**argv,**envp; int execlp(file,arg0,arg1,...,argn,0); char *file,*arg0,*arg1,...,*argn; int execvp(file,argv) char *file,**argv;

  17. wait系统调用 功能 等待进程的子进程终止,如果已经有子进程终止,则立即返回 函数原型 #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *stat_loc); 调用结果 函数返回值为已终止的子进程PID pid=wait(&status); status中含有子进程终止的原因 TERMSIG(status)为被杀信号 EXITSTATUS(status)为退出码

  18. 字符串库函数strtok char *strtok (char *str, char *tokens) 功能: returns a pointer to the first character after a token

  19. 最简单的shell:xsh0 main() { char buf[256],*cmd,*argv[100]; int n,sv; for(;;) { printf("=> "); if(fgets(buf,sizeof(buf),stdin)==NULL) exit(0); cmd=strtok(buf," \t\n"); if(cmd) { if(strcmp(cmd,"exit")==0) exit(0); n=0; argv[n++]=cmd; while(argv[n++]=strtok(NULL," \t\n")); if(fork()==0) { execvp(cmd,argv); fprintf(stderr,"** Bad command\n"); exit(1); } wait(&sv); } } }

  20. 执行xsh0 => => who am i root ttyp0 Nov 29 09:56 => ps -f UID PID PPID C STIME TTY TIME CMD root 1012 1011 0 09:56:00 ttyp0 00:00:00 login -c -p root 1020 1012 0 09:56:14 ttyp0 00:00:00 -csh root 1060 1020 2 10:36:37 ttyp0 00:00:00 xsh0 root 1062 1060 4 10:36:46 ttyp0 00:00:00 ps -f => ls -l *.c ls: *.c not found: No such file or directory (error 2) => mmx ** Bad command => ls -l xsh0 -rwxr--r-- 1 root other 43417 Dec 1 1998 xsh0 => exit

More Related