进程和task_struct

进程

什么是进程?
进程就是正在计算机上执行的实例。我们知道可执行文件都是存储在磁盘中,当计算机执行可执行文件时,才把可执行文件从磁盘中读取到内存上.然后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死亡状态:这个状态只是一个返回状态,不会在任务列表中看到
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章