进程就是程序动态运行的实例,是承担分配系统资源的实体。
进程信息被存放在一个叫进程控制块的数据结构中,将其称之为PCB。而Linux操作系统下的task_struct是PCB的一种,task_struct是Linux内核的一种数据结构,他会被装载到内存里并保存着进程的信息
信息分类如下:
状态:描述进程的状态,因为进程有挂起,阻塞,运行等好几个状态,所以都有个标识符来记录进程的执行状态。
内存指针:程序代码和进程相关数据的指针。
程序计数器:程序中即将被执行的下一条指令的地址。
上下文数据:进程执行时处理器的寄存器中的数据。
记账信息:包括处理器的时间总和,记账号等等。
标识符:与进程相关的唯一标识符,用来区别正在执行的进程和其他进程。
优先级:如果有好几个进程正在执行,就涉及到进程被执行的先后顺序的问题,这和进程优先级这个标识符有关。
I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和进程使用的文件列表等。
volatile long states;
状态 常见的可能取值:
TASK_RUNNING:表示进程正在执行或者处于准备执行的状态
TASK_INTERRUPTIBLE:进程因为等待某些条件处于阻塞(挂起的状态),一旦等待的条件成立,进程便会从该状态转化成就绪状态
TASK_UNINTERRUPTIBLE:意思与TASK_INTERRUPTIBLE类似,但是我们传递任意信号等不能唤醒他们,只有它所等待的资源可用的时候,他才会被唤醒。
TASK_STOPPED:进程被停止执行
TASK_TRACED:进程被debugger等进程所监视。
EXIT_ZOMBIE:进程的执行被终止,但是其父进程还没有使用wait()等系统调用来获知它的终止信息,此时进程成为僵尸进程
EXIT_DEAD:进程被杀死,即进程的最终状态。
TASK_KILLABLE:当进程处于这种可以终止的新睡眠状态中,它的运行原理类似于 TASK_UNINTERRUPTIBLE,只不过可以响应致命信号
unsigned long flags;
进程标志:
*PF_ALIGNWARN 打印“对齐”警告信息。
*PF_PTRACED 被ptrace系统调用监控。
*PF_TRACESYS 正在跟踪。
*PF_FORKNOEXEC 进程刚创建,但还没执行。
*PF_SUPERPRIV 超级用户特权。
*PF_DUMPCORE dumped core。
*PF_SIGNALED 进程被信号(signal)杀出。
*PF_STARTING 进程正被创建。
*PF_EXITING 进程开始关闭。
*PF_USEDFPU 该进程使用FPU(SMP only)。
*PF_DTRACE delayed trace (used on m68k)。
进程优先级,CPU分配资源的先后顺序就是进程的优先权。优先权高的有优先执行的权利。使用ps -l命令可以查看系统进程的相关信息,我们重点会关注到以下几个信息:
UID:代表执行者的身份
PID:代表这个进程的代号
PPID:代表该进程是由哪一个进程发展而来的,即其父进程代号
PRI:代表该进程的优先级,其值越小越先被执行
NI:代表该进程的nice值
NI:PRI值越小进程越先被执行,加入nice值后,PRI值就会被改变为
PRI(new) = PRI(old) + nice。nice取值的范围为[-20,19]。当nice值为负值时,进程的优先级值会减小,其对应的进程的优先级更高所以更先被执行。所以说,Linux下想要更改进程的优先级,只需要更改nice值即可。
修改优先级命令:
启动进程前调整:nice(例如:nice -n -2 ./test)
调整已存在进程nice:renice(例如:renice -3 -p 3267//PID为3267的进程的nice值设置为-3)
用top命令更改已存在进程的nice值:top进入以后输入r然后输入进程PID再输入nice值
上下文数据 (重要)
(1) struct desc_struct *ldt;
进程关于CPU段式存储管理的局部描述符表的指针,用于仿真WINE Windows的程序。其他情况下取值NULL,进程的ldt就是arch/i386/traps.c定义的default_ldt。
(2) struct thread_struct tss;
任务状态段,其内容与INTEL CPU的TSS对应,如各种通用寄存器.CPU调度时,当前运行进程的TSS保存到PCB的tss,新选中进程的tss内容复制到CPU的TSS。结构定义在include/linux/tasks.h中。
(3) unsigned long saved_kernel_stack;
为MS-DOS的仿真程序(或叫系统调用vm86)保存的堆栈指针。
(4) unsigned long kernel_stack_page;
在内核态运行时,每个进程都有一个内核堆栈,其基地址就保存在kernel_stack_page中。
进程队列指针
(1) struct task_struct *next_task,*prev_task;
所有进程(以PCB的形式)组成一个双向链表。next_task和就是链表的前后指针。链表的头和尾都是init_task(即0号进程)。
(2) struct task_struct *next_run,*prev_run;
由正在运行或是可以运行的,其进程状态均为TASK_RUNNING的进程所组成的一个双向循环链表,即run_queue就绪队列。该链表的前后向指针用next_run和prev_run,链表的头和尾都是init_task(即0号进程)。
(3) struct task_struct *p_opptr,*p_pptr;和struct task_struct *p_cptr,*p_ysptr,*p_osptr;
以上分别是指向原始父进程(original parent)、父进程(parent)、子进程(youngest child)及新老兄弟进程(younger sibling,older sibling)的指针。
进程标识
pid_t pid;//进程的唯一标识
pid_t tgid;//线程组的领头线程的pid成员的值
在Linux系统中,一个线程组中的所有线程使用和该线程组的领头线程(该组中的第一个轻量级进程)相同的PID,并被存放在tgid成员中。只有线程组的领头线程的pid成员才会被设置为与tgid相同的值。注意,getpid()系统调用返回的是当前进程的tgid值而不是pid值。(线程是程序运行的最小单位,进程是程序运行的基本单位。)
进程调度
int prio, static_prio, normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
unsigned int policy;
static_prio用于保存静态优先级,可以通过nice系统调用来进行修改。
rt_priority用于保存实时优先级。
normal_prio的值取决于静态优先级和调度策略(进程的调度策略有:先来先服务,短作业优先、时间片轮转、高响应比优先等等的调度算法)
prio用于保存动态优先级。
policy表示进程的调度策略,目前主要有以下五种:
#define SCHED_NORMAL 0//按照优先级进行调度(有些地方也说是CFS调度器)
#define SCHED_FIFO 1//先进先出的调度算法
#define SCHED_RR 2//时间片轮转的调度算法
#define SCHED_BATCH 3//用于非交互的处理机消耗型的进程
#define SCHED_IDLE 5//系统负载很低时的调度算法
#define SCHED_RESET_ON_FORK 0x40000000
SCHED_NORMAL用于普通进程,通过CFS调度器实现;
SCHED_BATCH用于非交互的处理器消耗型进程;
SCHED_IDLE是在系统负载很低时使用;
SCHED_FIFO(先入先出调度算法)和SCHED_RR(轮流调度算法)都是实时调度策略.
附:
以下是对task_struct的定义及注释:
struct task_struct {
volatile long state;
unsigned long flags;
int sigpending;
mm_segment_t addr_limit;
volatile long need_resched;
int lock_depth;
long nice;
unsigned long policy;
struct mm_struct *mm;
int processor;
unsigned long cpus_runnable, cpus_allowed;
struct list_head run_list;
unsigned long sleep_time;
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;
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;
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit;
struct completion *vfork_done;
unsigned long rt_priority;
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_value;
struct timer_list real_timer;
struct tms times;
unsigned long start_time;
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1;
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;
char comm[16];
int link_count, total_link_count;
struct tty_struct *tty;
unsigned int locks;
struct sem_undo *semundo;
struct sem_queue *semsleeping;
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;
};