进程
什么是进程?
进程就是正在计算机上执行的实例。我们知道可执行文件都是存储在磁盘中,当计算机执行可执行文件时,才把可执行文件从磁盘中读取到内存上.然后cpu从内存上读取指令来运行程序,那在内存上等待或者正在被cpu执行的程序就是进程。
操作系统是怎样标识进程的?
在进程执行时,anytime,进程总是被以下元素表示:
- 标识符:用以和其他进程区分,比如说PID
- 状态:表示程序当前状态,比如说是就绪,睡眠,正在执行等
- 程序计数器:程序即将被执行的下一条指令的地址
- 内存指针:一些和程序代码,进程相关数据,还有和其他进程共享的数据块的指针
- 上下文数据:程序执行时处理器和寄存器中的数据,比如说程序离开后通过这个又可以回来
- I/O状态信息:一些显示的I/O请求,分配给进程的I/O设备和被进程使用的头文件列表等
- 记账信息:包括处理器的时间总和,使用的时钟数总和,时间限制,记账号等
这些东西都保存在PCB(程序控制块)中,由专门的结构体来管理,在Linux中由task_struct结构体来管理,下面看一下0.11内核版本的task_struct结构体:
struct task_struct{
long state; //运行状态-1-unrunnable,1-runnable,0-stopped
long counter; //运行时间计数(滴答数)
long priority; //运行优先数,开始运行时counter = priority,越大运行越长
long signal; //信号,每个比特代表一种信号
struct sigaction sigaction[32];//信号执行属性结构
//对应信号要执行的操作和标志信息
long blocked; //进程信号屏蔽码(对应信号位图)
/****/
int exit_code;//任务执行停止的退出码,其父进程会取
unsigned long start_code;//代码段地址
unsigned long end_code;//代码段长度(字节数)
unsigned long end_data;//代码长度+数据长度(字节数)
unsigned long brk;//总长度(字节数)
unsigned long strat_stack;//堆栈段地址
long pid;//进程号
long father;//父进程号
long pgrp;//组进程号
long session;//会话号
long leader;//会话首领
unsigned short uid;//用户id
unsigned short euid;//有效用户id
unsigned short suid;//保存的用户id
unsigned short gid;//组id
unsigned short egid;//有效组id
unsigned short sgid;//保存的组id
long alarm;//报警定时值(滴答数)
long utime;//用户态运行时间(滴答数)
long stime;//系统运行时间(滴答数)
long cutime;//子进程用户态运行时间
long cstime;//子进程系统态运行时间
long start_time;//进程开始运行时刻
unsigned short usde_math;//标志:是否使用了协处理器
/******/
int tty;//进程使用tty的子设备号,-1表示没有使用
unsigned short umask;//文件创建属性屏蔽位
struct m_inode* pwd;//当前工作目录i结点结构
struct m_inode* root;//根目录i结点结构
struct m_inode* executable;//执行文件i结点结构
unsigned short close_on_exec;//执行时文件关闭文件句柄位图标志
struct file* filp[NP_OPEN];//进程使用的文件表结构
/******/
struct desc_struct ldt[3];//本任务的局部描述符,
//0-空,1-代码段cs,2-数据和堆栈段ds&ss
/*****/
struct tss_struct tss;//本进程任务状态段信息结构
}
通过fork()创建进程
一个现有的进程可以通过frok函数创建一个新的进程,由fork创建的新进程被称为子进程,其函数由两个返回值–子进程返回0,父进程返回子进程的PID,失败返回-1。子进程可以通过getpid函数获得父进程的PID。
执行fork后,子进程是父进程的副本,其获得父进程的数据空间,堆和栈的副本,等于是以父进程为模板,拷贝一份PCB,内存指针指向同一份代码,数据父子进程各自拥有一份, 父进程和子进程的执行顺序不确定, PC指针和父进程共用一份
子进程继承了父进程的:
- 实际用户ID,实际组ID,有效用户ID,有效组ID
- 附加组ID
- 进程组ID
- 会话ID
- 控制终端
- 文件描述符
- 设置用户ID标志和设置zuID标志
- 当前工作目录
- 根目录
- 文件模式创建屏蔽字
- 信号屏蔽和安排
- 针对任一打开文件描述符的在执行时关闭标志(close-on-exec)
- 环境
- 连接的共享存储段
- 存储映射
子进程和父进程的区别:
- fork的返回值
- 进程ID不同
- 子进程的tms_utime,tms_stime,tms_ctime以及tms_ustime被设置为0
- 父进程设置的文件锁
- 子进程未处理的闹钟被清除
- 子进程未处理的信号集被置空
进程状态
一个进程可以有不同的状态
- R运行状态:在运行中或者在运行队列里
- S睡眠状态:程序在等待世间的完成
- D磁盘休眠状态:在这个状态的进程通常会等待IO的结束
- T停止状态:可以通过发送SIGSTOP信号给进程来停止(T)进程,这个被停址的进程可以通过SIGCONT信号让进程继续运行
- X死亡状态:这个状态只是一个返回状态,不会在任务列表中看到