在Linux内核中,task_struct
是用于描述进程的核心数据结构,存储了进程的所有关键信息,包括进程ID、状态、调度信息、内存管理信息、文件描述符等。每个进程在内核中都对应一个 task_struct
结构体。
1. task_struct
的基本定义
task_struct
结构体的定义位于 include/linux/sched.h
头文件中。如下图所示,通过双向循环链表的方式将所有进程关联起来。
此结构体非常庞大, task_struct结构体中又包含了非常多的子结构体
由于task_struct内容较为庞大,这里列出部分关键字段:
struct task_struct {
volatile long state; // 进程状态 (TASK_RUNNING 等)
struct list_head tasks; // 进程链表 (所有进程通过该字段连接)
pid_t pid; // 进程 ID
pid_t tgid; // 线程组 ID (线程与主线程共享)
struct mm_struct *mm; // 进程的内存管理信息
struct thread_struct thread; // 进程的 CPU 相关信息 (寄存器等)
struct list_head children; // 子进程链表
struct task_struct *parent; // 父进程
struct files_struct *files; // 进程打开的文件信息
struct fs_struct *fs; // 进程的文件系统信息
struct signal_struct *signal;// 进程的信号处理信息
struct sched_entity se; // 进程的调度信息
};
2. task_struct
主要字段解析
(1)进程状态
state
:表示进程当前的状态,可能的取值包括:#define TASK_RUNNING 0 // 运行态或就绪态 #define TASK_INTERRUPTIBLE 1 // 可中断睡眠状态 #define TASK_UNINTERRUPTIBLE 2 // 不可中断睡眠状态 #define TASK_STOPPED 4 // 进程已停止 #define TASK_TRACED 8 // 进程被调试
(2)进程的标识
pid
:进程 ID,是 Linux 内核唯一标识一个进程的数值。tgid
:线程组 ID,同一进程的多个线程共享相同的tgid
,而主线程的pid == tgid
。
(3)进程调度
struct sched_entity se
:保存进程的调度信息,如优先级、时间片等,供 CFS(Completely Fair Scheduler,完全公平调度器) 使用。
(4)进程的内存管理
struct mm_struct *mm
:指向进程的内存管理结构,包含代码段、数据段、堆、栈等信息。mm->pgd
:页全局目录(Page Global Directory),用于地址转换。mm->mmap
:存储该进程的虚拟内存区域(VMA,Virtual Memory Area)。
struct fs_struct *fs
:文件系统信息,比如cwd
(当前工作目录)。
(5)进程的关系
struct task_struct *parent
:指向父进程。struct list_head children
:指向该进程创建的子进程列表。
(6)进程的文件管理
struct files_struct *files
:保存进程打开的所有文件的描述符信息,如fd
。
3.线程
task_struct 既表示进程,也表示线程
Linux 内核不区分进程和线程,所有的执行实体(tasks)都是 task_struct 结构体的一个实例。
线程和进程的主要区别在于:
- 进程:有独立的地址空间(mm_struct)。
- 线程:共享同一个地址空间(mm_struct),但 task_struct 依然是独立的。
- Linux 线程创建时,调用 clone() 系统调用,最终创建一个新的 task_struct,但其 mm_struct 指针与父线程共享。
在Linux中,线程和进程的主要数据结构都是 task_struct,并不是 thread_info。
task_struct
是 Linux 内核中表示进程和线程的主要数据结构,而thread_info
只是一个与task_struct
关联的辅助结构,不能直接等同于线程的数据结构。
4. 进程的创建与 task_struct
Linux 创建进程主要通过 fork()
、clone()
或 kernel_thread()
,内核会:
调用
copy_process()
:为新进程分配
task_struct
。复制父进程的部分信息,如
pid
、mm
、files
。根据
clone
标志决定哪些资源共享(如文件、地址空间)。
将
task_struct
插入进程链表:task_struct
通过tasks
链接到init_task
全局变量,实现进程管理。
5. task_struct
在内存中的存放
在 Linux 早期版本,task_struct
直接存放在 内核态栈 的底部,但由于 task_struct
变得越来越大,现代 Linux 将其单独分配在 slab
内存池 中。