进程的状态与task_struct结构体
2018-03-23 20:49
423 查看
一、什么是进程
进程,就是程序的一个执行实例,或正在执行的程序。
详细介绍请看点击打开链接
那么进程在Linux中有几种状态呢?如下:
1、R
处于运行或可运行状态,即进程正在运行或在运行队列(可执行队列)中等待。只有在该状态的进程才可能在CPU上运行,同一时刻可能有多个进程处于该状态。
(注:很多教科书上将正在CPU上执行的进程的状态定义为Running,将可执行但尚未被调度执行的进程状态定义为Ready,这2种状态在Linux下统一为R状态)
2、S
处于可中断的睡眠状态,即进程在休眠中,由于在等待某个事件的完成(或等待某个条件的形成或等待某个信号等)
(注:等待socket连接、等待信号量等)而被挂起;当这些事件发生时,对应的等待队列中的一个或多个进程将被唤醒。一般情况下,进程列表中绝大多数进程都处于该状态。
3、D
处于不可中断的睡眠状态,不可中断指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号,无法用kill命令杀死,进程必须等待直到有中断发生。
4、T
处于暂停或跟踪状态。进程收到SIGSTOP、SIGSTP、SIGTIN、SIGTOU等信号进入暂停状态(除非进程处于不可中断的睡眠状态);当接着向进程发送1个SIGCONT信号,进程可以从暂停状态恢复到运行或能运行状态。
当进程被跟踪时,它处于被跟踪状态。“被跟踪”指进程暂停下来,等待跟踪它的进程对它进行操作。例如在GDB调试中,对被跟踪的进程设置某个断点,进程执行到断点处停下来的时候就处于被跟踪状态。
暂停与跟踪状态还是有区别的,被跟踪状态相当于在暂停状态之上多了一层保护,处于被跟踪状态的进程不能响应SIGCONT信号而被唤醒,只能等到调试进程通过ptrace系统调用执行ptrace_cont、ptrace_detach等操作(通过ptrace系统调用的参数指定操作),或调试进程退出,被调试的进程才能恢复到R状态。
5、Z
处于僵死状态,也称退出状态。它指进程已经结束,放弃了几乎所有的内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置来记载该进程的退出状态等信息(task_struct结构体[保存了该进程的退出码])供其他进程收集。
6、X
进程在退出过程中可能不会保留它的task_struct。例如某个进程是多线程程序中被detach过的进程;或者父进程通过设置SIGCHLD信号的Handler为SIG_IGN,显示的忽略了SIGCHLD信号。
此时该进程被置于exit_dead退出状态,这意味着接下来的代码立即会将该进程彻底释放。故exit_dead状态非常短暂,几乎不可能通过ps命令捕捉到。
二、模拟实现僵尸进程与孤儿进程
1、僵尸进程
Makefile文件:
jiangshi.c
2、孤儿进程
Makefile文件
guer.c
三、task_struct结构体
每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linus内核的进程控制块是task_struct的结构体
进程,就是程序的一个执行实例,或正在执行的程序。
详细介绍请看点击打开链接
那么进程在Linux中有几种状态呢?如下:
1、R
处于运行或可运行状态,即进程正在运行或在运行队列(可执行队列)中等待。只有在该状态的进程才可能在CPU上运行,同一时刻可能有多个进程处于该状态。
(注:很多教科书上将正在CPU上执行的进程的状态定义为Running,将可执行但尚未被调度执行的进程状态定义为Ready,这2种状态在Linux下统一为R状态)
2、S
处于可中断的睡眠状态,即进程在休眠中,由于在等待某个事件的完成(或等待某个条件的形成或等待某个信号等)
(注:等待socket连接、等待信号量等)而被挂起;当这些事件发生时,对应的等待队列中的一个或多个进程将被唤醒。一般情况下,进程列表中绝大多数进程都处于该状态。
3、D
处于不可中断的睡眠状态,不可中断指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号,无法用kill命令杀死,进程必须等待直到有中断发生。
4、T
处于暂停或跟踪状态。进程收到SIGSTOP、SIGSTP、SIGTIN、SIGTOU等信号进入暂停状态(除非进程处于不可中断的睡眠状态);当接着向进程发送1个SIGCONT信号,进程可以从暂停状态恢复到运行或能运行状态。
当进程被跟踪时,它处于被跟踪状态。“被跟踪”指进程暂停下来,等待跟踪它的进程对它进行操作。例如在GDB调试中,对被跟踪的进程设置某个断点,进程执行到断点处停下来的时候就处于被跟踪状态。
暂停与跟踪状态还是有区别的,被跟踪状态相当于在暂停状态之上多了一层保护,处于被跟踪状态的进程不能响应SIGCONT信号而被唤醒,只能等到调试进程通过ptrace系统调用执行ptrace_cont、ptrace_detach等操作(通过ptrace系统调用的参数指定操作),或调试进程退出,被调试的进程才能恢复到R状态。
5、Z
处于僵死状态,也称退出状态。它指进程已经结束,放弃了几乎所有的内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置来记载该进程的退出状态等信息(task_struct结构体[保存了该进程的退出码])供其他进程收集。
6、X
进程在退出过程中可能不会保留它的task_struct。例如某个进程是多线程程序中被detach过的进程;或者父进程通过设置SIGCHLD信号的Handler为SIG_IGN,显示的忽略了SIGCHLD信号。
此时该进程被置于exit_dead退出状态,这意味着接下来的代码立即会将该进程彻底释放。故exit_dead状态非常短暂,几乎不可能通过ps命令捕捉到。
二、模拟实现僵尸进程与孤儿进程
1、僵尸进程
Makefile文件:
1 2 .PHONY:jiangshi 3 4 jiangshi:jiangshi.c 5 gcc -o $@ $^ 6 7 .PHONY:clean 8 clean: 9 rm -f jiangshi
jiangshi.c
1 #include<stdio.h> 2 #include<stdlib.h> 3 int main(){ 4 pid_t id=fork(); 5 if(id<0){ 6 perror("fork"); 7 return 1; 8 } 9 else if(id>0){//parent 10 printf("parent[%d] is sleeping...\n",getpid()); 11 sleep(30); 12 } 13 else{ 14 printf("child[%d] is begin Z...\n",getpid()); 15 sleep(5); 16 exit(EXIT_SUCCESS); 17 } 18 return 0; 19 }
2、孤儿进程
Makefile文件
1 2 3 .PHONY:guer 4 5 guer:guer.c 6 gcc -o $@ $^ 7 8 .PHONY:clean 9 clean: 10 rm -f guer
guer.c
1 #include<unistd.h> 2 #include<stdio.h> 3 #include<stdlib.h> 4 int main(){ 5 pid_t id=fork(); 6 if(id<0){ 7 perror("fork"); 8 return 1; 9 } 10 else if(id==0){//child 11 printf("I am child,pid:%d\n",getpid()); 12 sleep(10); 13 } 14 else{//parent 15 printf("I am parent,pid:%d\n",getpid()); 16 sleep(3); 17 exit(0); 18 } 19 return 0; 20 }
三、task_struct结构体
每个进程在内核中都有一个进程控制块(PCB)来维护进程相关的信息,Linus内核的进程控制块是task_struct的结构体
struct task_struct { volatile long state; //说明了该进程是否可以执行,还是可中断等信息 unsigned long flags; //Flage 是进程号,在调用fork()时给出 int sigpending; //进程上是否有待处理的信号 mm_segment_t addr_limit; //进程地址空间,区分内核进程与普通进程在内存存放的位置不同 //0-0xBFFFFFFF for user-thead //0-0xFFFFFFFF for kernel-thread //调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度 volatile long need_resched; int lock_depth; //锁深度 long nice; //进程的基本时间片 //进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR, 分时进程:SCHED_OTHER unsigned long policy; struct mm_struct *mm; //进程内存管理信息 int processor; //若进程不在任何CPU上运行, cpus_runnable 的值是0,否则是1 这个值在运行队列被锁时更新 unsigned long cpus_runnable, cpus_allowed; struct list_head run_list; //指向运行队列的指针 unsigned long sleep_time; //进程的睡眠时间 //用于将系统中所有的进程连成一个双向循环链表, 其根是init_task struct task_struct *next_task, *prev_task; struct mm_struct *active_mm; struct list_head local_pages; //指向本地页面 unsigned int allocation_order, nr_local_pages; struct linux_binfmt *binfmt; //进程所运行的可执行文件的格式 int exit_code, exit_signal; int pdeath_signal; //父进程终止时向子进程发送的信号 unsigned long personality; //Linux可以运行由其他UNIX操作系统生成的符合iBCS2标准的程序 int did_exec:1; pid_t pid; //进程标识符,用来代表一个进程 pid_t pgrp; //进程组标识,表示进程所属的进程组 pid_t tty_old_pgrp; //进程控制终端所在的组标识 pid_t session; //进程的会话标识 pid_t tgid; int leader; //表示进程是否为会话主管 struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr; struct list_head thread_group; //线程链表 struct task_struct *pidhash_next; //用于将进程链入HASH表 struct task_struct **pidhash_pprev; wait_queue_head_t wait_chldexit; //供wait4()使用 struct completion *vfork_done; //供vfork() 使用 unsigned long rt_priority; //实时优先级,用它计算实时进程调度时的weight值 long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS]; //内存缺页和交换信息: //min_flt, maj_flt累计进程的次缺页数(Copy on Write页和匿名页)和主缺页数(从映射文件或交换 //设备读入的页面数); nswap记录进程累计换出的页面数,即写到交换设备上的页面数。 //cmin_flt, cmaj_flt, cnswap记录本进程为祖先的所有子孙进程的累计次缺页数,主缺页数和换出页面数。 //在父进程回收终止的子进程时,父进程会将子进程的这些信息累计到自己结构的这些域中 unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap; int swappable:1; //表示进程的虚拟地址空间是否允许换出 //进程认证信息 //uid,gid为运行该进程的用户的用户标识符和组标识符,通常是进程创建者的uid,gid //euid,egid为有效uid,gid //fsuid,fsgid为文件系统uid,gid,这两个ID号通常与有效uid,gid相等,在检查对于文件 //系统的访问权限时使用他们。 //suid,sgid为备份uid,gid uid_t uid,euid,suid,fsuid; gid_t gid,egid,sgid,fsgid; int ngroups; //记录进程在多少个用户组中 gid_t groups[NGROUPS]; //记录进程所在的组 //进程的权能,分别是有效位集合,继承位集合,允许位集合 kernel_cap_t cap_effective, cap_inheritable, cap_permitted; int keep_capabilities:1; struct user_struct *user; struct rlimit rlim[RLIM_NLIMITS]; //与进程相关的资源限制信息 unsigned short used_math; //是否使用FPU char comm[16]; //进程正在运行的可执行文件名 //文件系统信息 int link_count, total_link_count; //NULL if no tty 进程所在的控制终端,如果不需要控制终端,则该指针为空 struct tty_struct *tty; unsigned int locks; //进程间通信信息 struct sem_undo *semundo; //进程在信号灯上的所有undo操作 struct sem_queue *semsleeping; //当进程因为信号灯操作而挂起时,他在该队列中记录等待的操作 //进程的CPU状态,切换时,要保存到停止进程的task_struct中 struct thread_struct thread; //文件系统信息 struct fs_struct *fs; //打开文件信息 struct files_struct *files; //信号处理函数 spinlock_t sigmask_lock; struct signal_struct *sig; //信号处理函数 sigset_t blocked; //进程当前要阻塞的信号,每个信号对应一位 struct sigpending pending; //进程上是否有待处理的信号 unsigned long sas_ss_sp; size_t sas_ss_size; int (*notifier)(void *priv); void *notifier_data; sigset_t *notifier_mask; u32 parent_exec_id; u32 self_exec_id; spinlock_t alloc_lock; void *journal_info; };
相关文章推荐
- task_struct解析(一) 进程状态
- 进程以及task_struct结构体
- Linux进程的管理与调度(一)--- Linux进程描述符task_struct结构体详解
- linux进程管理与调度:task_struct结构体
- task_struct结构体及僵尸、孤儿进程
- 进程与task_struct结构体
- Linux进程描述符task_struct结构体详解--Linux进程的管理与调度
- linux内核学习之进程管理------task_struct结构体
- Linux中进程描述符task_struct结构体详解
- Linux进程管理之task_struct结构体(上)
- linux下的进程描述符task_struct 结构体认识
- Linux进程管理之task_struct结构体(下)
- Linux进程描述符:task_struct结构体
- Linux进程管理之task_struct结构体
- task_struct解析(一) 进程状态
- Linux进程管理之task_struct结构体
- linux编程之进程编程(5)---- 进程管理(task_struct结构体)
- linux进程task_struct结构体中的state域
- Linux进程描述符:task_struct结构体
- Linux的进程,线程以及调度(fork与僵尸,内存泄漏,task结构体,停止状态与作业控制)