来谈谈Linux中的task_struct结构体

本文详细介绍了Linux中的进程概念,包括进程的基本属性、状态变化、进程模型及task_struct数据结构解析等内容,帮助读者深入理解进程管理和调度机制。

在介绍task_struct,我们要先来看几个概念

一:进程的概念

      1. 从用户角度来看:进程是程序的一次动态执行过程

      2.从内核角度看:

                              

  3.那PCB结构中的数据有哪些呢

                                             

4.在进程执行的任意时刻,都可由如下元素来表征

  • 标识符:与进程相关的唯一标识符,用来区别正在执行的进程和其他进程
  • 状态:描述进程的状态,因为进程有挂起,阻塞,运行等好几个状态,所以都有个标识符来记录进程的执行状态
  • 优先级:如果有好几个进程正在执行,就涉及到进程被执行的先后顺序的问题,这和进程优先级这个标识符有关。
  • 程序计数器:程序中即将被执行的下一条指令的地址
  • 内存指针:程序代码和进程相关数据的指针。
  • 上下文数据:进程执行时处理器的寄存器中的数据
  • I / O状态信息:包括显示的I / O请求,分配给进程的I / O设备和被进程使用的文件列表等
  • 记账信息:包括处理器的时间总和,记账号等等   

5.进程标识符


6.进程创建的一般过程


二:进程模型

1.两状态模型

在任何时刻,一个进程要么正在执行,要么未执行,因而可以构建最简单的模型


2.五状态模型

(1)运行态:进程正在执行。

(2)就绪态:进程做好了准备,只要有机会就开始执行。

(3)阻塞态:进程在某些事情发生前不能执行

(4)新建态:刚刚创建的进程

(5)退出态:操作系统从可执行进程组中释放出的进程


3.经典Linux七态


三.task_struct的源码成员解析

task_struct头文件sched.h链接https://elixir.bootlin.com/linux/latest/source/include/linux/sched.h

(1)进程状态

/* -1 unrunnable, 0 runnable, >0 stopped: */

volatile longstate;

上面这个变量就是描述进程状态的成员,结合Ç语言我们学到的知识挥发性关键字是降低编译器对代码的优化,是状态变量一直从变量的内存中读取内容而不是寄存器;从而保证对操作系统状态实时访问的稳定性。

(2)成员的可能取值如下

/*
 * Task state bitmask. NOTE! These bits are also
 * encoded in fs/proc/array.c: get_task_state().
 *
 * We have two separate sets of flags: task->state
 * is about runnability, while task->exit_state are
 * about the task exiting. Confusing, but this way
 * modifying one set can't modify the other one by
 * mistake.
 */

/* Used in tsk->state: */
#define TASK_RUNNING			0x0000
#define TASK_INTERRUPTIBLE		0x0001
#define TASK_UNINTERRUPTIBLE		0x0002
#define __TASK_STOPPED			0x0004
#define __TASK_TRACED			0x0008
/* Used in tsk->exit_state: */
#define EXIT_DEAD			0x0010
#define EXIT_ZOMBIE			0x0020
#define EXIT_TRACE			(EXIT_ZOMBIE | EXIT_DEAD)
/* Used in tsk->state again: */
#define TASK_PARKED			0x0040
#define TASK_DEAD			0x0080
#define TASK_WAKEKILL			0x0100
#define TASK_WAKING			0x0200
#define TASK_NOLOAD			0x0400
#define TASK_NEW			0x0800
#define TASK_STATE_MAX			0x1000
我们可以看到变量定义后面的注释,它说明变量内容<0是不运行的,=0是运行状态,>0是停止状态。

(3)

状态描述
TASK_RUNNING表示进程正在执行或者处于准备执行的状态
TASK_INTERRUPTIBLE进程因为等待某些条件处于阻塞(挂起的状态),一旦等待的条件成立,进程便会从该状态转化成就绪状态
TASK_UNINTERRUPTIBLE意思与TASK_INTERRUPTIBLE类似,但是我们传递任意信号等不能唤醒他们,只有它所等待的资源可用的时候,他才会被唤醒。
TASK_STOPPED进程被停止执行
TASK_TRACED进程被debugger等进程所监视。
EXIT_ZOMBIE进程的执行被终止,但是其父进程还没有使用wait()等系统调用来获知它的终止信息,此时进程成为僵尸进程
EXIT_DEAD进程被杀死,即进程的最终状态。
TASK_KILLABLE当进程处于这种可以终止的新睡眠状态中,它的运行原理类似于 TASK_UNINTERRUPTIBLE,只不过可以响应致命信号
(4)进程标识符

pid_t pid;//进程的标识符

pid_t tgid;//线程组标识符//进程标识符就不用解释了,它的引入是为了区别每个进程;

tgid的引入是由于Unix程序员希望同一组线程具有相同的pid所以就引入了tgid.

(5)进程标记符

    unsignedint flags; /* per process flags, defined below */

flags反应进程的状态信息,用于内核识别当前进程的状态。

取值范围如下:

/*
 * Per process flags
 */
#define PF_IDLE			0x00000002	/* I am an IDLE thread */
#define PF_EXITING		0x00000004	/* Getting shut down */
#define PF_EXITPIDONE		0x00000008	/* PI exit done on shut down */
#define PF_VCPU			0x00000010	/* I'm a virtual CPU */
#define PF_WQ_WORKER		0x00000020	/* I'm a workqueue worker */
#define PF_FORKNOEXEC		0x00000040	/* Forked but didn't exec */
#define PF_MCE_PROCESS		0x00000080      /* Process policy on mce errors */
#define PF_SUPERPRIV		0x00000100	/* Used super-user privileges */
#define PF_DUMPCORE		0x00000200	/* Dumped core */
#define PF_SIGNALED		0x00000400	/* Killed by a signal */
#define PF_MEMALLOC		0x00000800	/* Allocating memory */
#define PF_NPROC_EXCEEDED	0x00001000	/* set_user() noticed that RLIMIT_NPROC was exceeded */
#define PF_USED_MATH		0x00002000	/* If unset the fpu must be initialized before use */
#define PF_USED_ASYNC		0x00004000	/* Used async_schedule*(), used by module init */
#define PF_NOFREEZE		0x00008000	/* This thread should not be frozen */
#define PF_FROZEN		0x00010000	/* Frozen for system suspend */
#define PF_KSWAPD		0x00020000	/* I am kswapd */
#define PF_MEMALLOC_NOFS	0x00040000	/* All allocation requests will inherit GFP_NOFS */
#define PF_MEMALLOC_NOIO	0x00080000	/* All allocation requests will inherit GFP_NOIO */
#define PF_LESS_THROTTLE	0x00100000	/* Throttle me less: I clean memory */
#define PF_KTHREAD		0x00200000	/* I am a kernel thread */
#define PF_RANDOMIZE		0x00400000	/* Randomize virtual address space */
#define PF_SWAPWRITE		0x00800000	/* Allowed to write to swap */
#define PF_NO_SETAFFINITY	0x04000000	/* Userland is not allowed to meddle with cpus_allowed */
#define PF_MCE_EARLY		0x08000000      /* Early kill for mce process policy */
#define PF_MUTEX_TESTER		0x20000000	/* Thread belongs to the rt mutex tester */
#define PF_FREEZER_SKIP		0x40000000	/* Freezer should not count it as freezable */
#define PF_SUSPEND_TASK		0x80000000      /* This thread called freeze_processes() and should not be frozen */
常用状态
状态描述
PF_FORKNOEXEC表示进程刚被创建,但还没有执行
PF_SUPERPRIV表示进程拥有超级用户特权
PF_SIGNALED表示进程被信号杀出
PF_EXITING表示进程开始关闭

(6)表示进程亲属关系的成员

/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->real_parent->pid)
*/
struct task_struct __rcu *real_parent; /* real parent process */
struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
/*
* children/sibling forms the list of my natural children
*/
struct list_head children; /* list of my children */
成员描述
real_parent指向当前操作系统执行进程的父进程,如果父进程不存在,指向pid为1的init进程
paren指向当前进程的父进程,当当前进程终止时,需要向它发送wait4()的信号
children位于链表的头部,链表的所有元素都是children的子进程
group_leader指向进程组的领头进程
(7)ptrace系统调用
Ptrace提供了一种父进程,它可以被用来控制子进程的运行,常被用来进行断点调试,当它被设置为0时表示不需要追踪。
(8)进程调度
优先级
int prio, static_prio, normal_prio;
unsigned int rt_priority;
成员描述
static_prio用来保存静态优先级,可以调用nice系统直接来修改取值范围为100~139
rt_priority用来保存实时优先级,取值范围为0~99
prio用来保存动态优先级
normal_prio它的值取决于静态优先级和调度策略
实时优先级和静态优先级的取值范围中,值越大,优先级越高

(9)进程地址空间


成员描述
mm进程所拥有的内存空间描述符,对于内核线程的mm为NULL
active_mm指进程运行时所使用的进程描述符
rss_stat被用来记录缓冲信息

Linux系统中,内核通过`task_struct`结构体来管理进程,该结构体包含了一个进程所需的所有信息,定义在`include/linux/sched.h`文件中,它实际上就是进程控制块(PCB),会被装载到RAM中,每个进程都把它的信息放在这个结构体中[^1][^2][^3]。 `task_struct`结构体成员繁多,以下是一些主要成员及其解析: - **进程的状态**: ```c volatile long state; ``` `state`表示进程的状态,`-1`表示不可运行状态,`0`表示可运行状态,大于零表示停止状态。这里的`volatile`是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值[^2]。 - **进程的标识符**:每个进程都有唯一的标识符,用于区分不同的进程。 - **调度信息**:包含由哪个调度函数调度、怎样调度等信息,内核依据这些信息来决定进程的执行顺序和时间片分配。 - **进程的通讯状态**:记录进程在进程间通信(IPC)中的状态,如是否正在等待消息、是否有未处理的信号等。 - **进程树指针**: ```c struct task_struct *parent; struct list_head children; ``` `parent`指向父进程的`task_struct`,`children`是一个链表头,用于连接该进程的所有子进程,通过这些指针可以构建出进程树的结构。 - **时间信息**:记录进程的执行时间,如进程已经执行的CPU时间、最近一次被调度的时间等,以便CPU进行合理的资源分配。 - **文件信息**: ```c struct files_struct *files; ``` `files`指向一个`files_struct`结构体,该结构体包含了进程打开的所有文件描述符和相关信息,用于管理进程的文件操作。 - **进程上下文和内核上下文**:保存进程在用户态和内核态下的执行上下文,包括寄存器值、栈指针等,当进程在用户态和内核态之间切换时,需要保存和恢复这些上下文信息。 - **处理器上下文**:记录进程在特定处理器上的执行状态,如处理器的寄存器状态等。 - **内存信息**: ```c struct mm_struct *mm; ``` `mm`指向一个`mm_struct`结构体,该结构体包含了进程的内存管理信息,如虚拟地址空间、页表等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值