分类: LINUX
2010-07-16 21:54:14
进程是linux系统下用户层管理事务的基本单位,每个进程有自己独立运行环境和系统资源,进程的环境有当前系统状态和父进程信息决定和组成;include/linux/sched.h定义结构体struct task_struct来管理每个进程的资源,该结构体包括:线程的基本信息、内存信息、tty终端信息、当前目录信息、打开的文件描述符信息、信号信息;进程还有其他属性:pid,ppid,uid,euid等。结构体详细解释见附件《《进程pcb结构体详细解释》》。
l 从程序的角度来说:程序是处于某个目录下的一个可执行文件,如果运行需要通过装载器将其加载到内存中才可以运行;相对程序来说进程,进程是程序执行的实例,不仅是独立运行的实例,而且也是独立竞争资源的实体。区别与程序:程序是静态的,是保存在磁盘上的指令的有序集合;进程是一个动态的概念,是程序执行的过程,包括创建、调度和消亡的整个过程。
l 从线程角度来说:进程定义为一个其中运行有一个或者多个线程的地址空间和线程要求使用的系统资源。
可执行文件(程序)在存储时(没有调入内存)时分为:代码区(text)、数据区(data)和未初始化区(bss)3部分;
² 代码区:存放cpu执行的机器指令(machine instructions),可共享的,指令包括操作码和操作对象(或对象地址引用),如为立即数将直接包含在代码中,如局部数据将在运行时在栈区分配空间,然后在引用该数据地址,如在bss区和数据区,在代码中同样将引用数据的地址。
² 数据区:(全局初始化数据区、静态数据区)全局变量和静态变量和常量数据。
² 未初始化区:bbs(block started by symbol)未初始化的全局变量和静态变量。
Linux系统下,一旦可执行文件被加载到内存中运行则演变成一个或多个的进程;一个进程主要包括在内存申请的空间,代码区、初始化数据区、未初始化数据区、堆区和栈区5个部分:
² 代码区:加载的可执行文件代码,加载到内存的位置有加载器来完成,如果是自己移植的操作系统,则需要事先的规划各加载位置。
² 全局初始化区/静态数据区:生命周期为整个程序的运行过程
² 未初始化区(bss):生命周期为整个程序的运行过程
² 堆区(heap):动态内存分配,位于bss区和栈区之间。注意分配和释放
² 栈区(stack):有编译器自动分配,存放函数的参数值,返回值以及局部变量等,在运
² 行过程中实时的加载和释放。
用户级进程拥有以下几种状态,所有的进程都在以下几种状态间切换:
² 就绪状态(TASK_RUNNING):进程已经具备执行一切条件等待cpu的分配处理
² 可执行状态(TASK_RUNNING):进程正占用cpu运行
² 等待状态(TASK_INTERRUPTIBLE/TASK_UNINTERRUPTIBLE):
² 可中断等待:进程等待某事件的发生,处于等待队伍中等待资源有效时唤醒,并可被中断
² 不可中断等待:进程等待某事件的发生,处于等待队伍中等待资源有效时唤醒但不可被中断
² 停止状态:(TASK_STOP)进程已经结束,已经释放了相应的资源,但未释放进程控制块pcb,处于该状态的进程可以被唤醒。
² 僵死状态:TASK_ZOMBIE 即将重任务链表删除,但在task中依然由一个task_struct数据结构,等待父进程释放。
//usr/include/unistd.h>
² 进程号(PID):extern _pid_t getpid(void);
² 父进程号(PPID)extern _pid_t getppid(void);
² 进程组号(PGID)extern _pid_t getpgid(void);
² 真实用户号(RUID)extern _pid_t getruid(void);
² 真实用户组号(RGID)extern _pid_t getrgid(void);
² 有效用户号(EUID)extern _pid_t geteuid(void);
² 有效用户组号(EGID)extern _pid_t getegid(void);
创建进程的两种方式:
1. 复制进程映像
Exitern _pid_t fork(void)
返回值:
成功 返回子进程的pid以及在子进程返回0,以区分父子进程
失败 返回-1
Fork创建子进程后,子进程将复制父进程的数据段、bss段、代码段、堆空间、栈空间和文件描述符,而对于文件描述关联的内核文件表项采用共享的方式。“子进程是父进程的一个复制品”
2. 替换进程映像
Exitern _pid_t vfork(void)
成功在子进程环境中返回0;在父进程环境中返回子进程的进程号。
Vfork():
l 不是完全将父进程的地址空间复制到子进程中
l 保证子进程先运行,在子进程调用exec或exit之后父进程才能被调度运行
l 装载另一个程序。
l 进程号(PID):extern _pid_t getpid(void);
l 父进程号(PPID)extern _pid_t getppid(void);
l 进程组号(PGID)extern _pid_t getpgid(void);
l 真实用户号(RUID)extern _pid_t getruid(void);
l 真实用户组号(RGID)extern _pid_t getrgid(void);
l 有效用户号(EUID)extern _pid_t geteuid(void);
l 有效用户组号(EGID)extern _pid_t getegid(void);
l Access核实用户权限:Extern int access(_const char *name,int _type);
功能:检查真实用户号或真实用户组号是否拥有对文件的相应访问权限;
Name:文件名
Type: R_OK 4 读权限
W_OK 2 写权限
X_OK 1 执行权限
F_OK 0 文件是否存在
l 设置真实用户ruid:extern int setuid(_uid_t uid);
l 设置有效用户euid:extern int seteuid(_uid_t uid);
Exec函数族:
当调用一种exec函数时,该进程执行的程序完全替代为新程序
Int execl(const char *path,const char *arg0,......,(char *)0 )
Int execv(const char *path,const char *argv[ ])
Int execlp(const char *path,const char *arg0,......,(char *)0)
Int execvp(const char *path,const char *argv[ ])
Int execle(const char *filename,const char *arg0,......,(char *)0,char *const env[ ])
Int execve(const char *filename,const char *argv[ ],char *const env[ ])
/usr/include/sys/wait.h
l Wait()等待子进程结束,
Extern pid_t wait(_WAIT_STATUS _stat_loc)
#宏 WIFEXITED(status)// 判断是否正常退出
#宏 WIFEXITED(status) // 取得子进程的exit()返回状态值
#宏 WIFSIGNALED(status)// 判断是否为因信号而结束
#宏 WTERMSIG(status) //取得因信号中止的信号代码
v#宏 WIFSTOPPED(status) //进程是否处于暂停执行
#宏 WSTOPSIG(status) // 取得引发子进程暂停的信号代码
l Waitpid()等待子进程结束
Extern pid_t waitpid(_pid_t pid,int *stat_loc,int option)
Option:0、WNOHANG 不阻塞等待、WUNTRACED 报告状态信息
1. 向exit或_exit发布一个调用
l Exit()正常结束当前的进程,并把参数返回给父进程,进程所有的缓冲区数据会自动写回并关闭文件
l Void _exit(int status):立即结束目前的进程执行,并将参数返回给父进程,并关闭未关闭的文件,此函数调用后不会返回,并且会传递sigchid信号给父进程,父进程可以由wait函数取得子进程结束状态。要点:不会处理标准io的缓冲区,exit会处理缓冲区。
l Int On_exit(void (*function)(int,void*),void *arg):设置一个程序正常结束前调用的函数,成功返回0,否则-1;
l Int at_exit(void(*function)(void)):用来设置一个程序正常结束前调用的函数
l Abort中止进程
2. 在main函数中执行return
l Return退出当前的函数体,exit()函数退出当前的进程,在main函数中return(0)和exit(0)相同功能
l Return仅仅从子函数中返回,如果子进程用exit()退出,调用exit时要调用一段终止处理程序,然后关闭所有的io流
3. 隐含的离开main函数