本系列文章将重点学习分析进程的相关内容,包括进程的基本概念,进程的创建,fork,vfork,clone等系统调用是如何创建进程的,linux内核是如何描述一个进程的,以及进程的调度算法学习,比如CFS调度算法等相关内容。
其中前提的准备工作:
学习过程中会通过实践+阅读内核源代码+图文并茂的方式来呈现进程管理的相关内容。
当自己写了一个简单的hello_world程序后,然后打印在控制台。
难道大家没有思考如下的几个问题嘛
当学习过进程管理后,你就很清楚的知道,自己写的程序时如何运行的? 何时被CPU调度的? 何时放弃CPU? 何时睡眠等。所以我们必须翻阅这座山。
程序就可以简单的理解是程序语言为了完成某种功能的一个数据集合。
#include <stdio.h>
int main()
{
printf("Hello_world!\n");
return 0;
}
比如上述的hello_world程序,就是由C语言组成的一个数据的集合。
将这段程序编译,然后在计算机中运行起来之后就变为了进程
进程 = 程序 + 执行
在大学的操作系统中肯定学过这样一段话:进程是最小资源分配的基本单位,线程是调度的基本单位,也称线程为轻量级进程。
比如对于上面的hello_world程序,如果想要在操作系统中运行就必须给分配相应的资源,比如内存资源。比如通过如下命令获取子程序的各个段
可以看到一个进程如果要正在运行起来,操作系统肯定会给它分配各个段,比如上面的代码段,数据段,堆栈段等等
总结:
上面说过进程是一个有生命的个体,既然有生命就存在创建,活动,停止,销毁等状态。
上面的图片描述一个5种常见的状态
linux内核中使用task_struct结构来描述一个进程
struct task_struct {
volatile long state;
void *stack;
int on_rq;
int prio;
int static_prio;
int normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
unsigned int policy;
int nr_cpus_allowed;
cpumask_t cpus_allowed;
struct mm_struct *mm;
struct mm_struct *active_mm;
int exit_state;
int exit_code;
int exit_signal;
pid_t pid;
pid_t tgid;
char comm[TASK_COMM_LEN];
/* Filesystem information: */
struct fs_struct *fs;
/* Open file information: */
struct files_struct *files;
/* Namespaces: */
struct nsproxy *nsproxy;
/* Signal handlers: */
struct signal_struct *signal;
......
}
此结构体在5.0的内核中长达600多行,这里我们只挑一些重点的字段说下。
/* 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
上面说了进程是资源分配的基本单位,那一个进程中肯定包含着这个进程运行起来的资源,比如mm内存资源,fs文件系统资源,files文件资源,signal信号资源等。
上图是Linux中的经典的进程状态,增加了暂停和僵死两种状态,将祖塞状态分为TASK_INTERRUPTBLE(可中断)和TASK_UNINTERRUPTIBLE(不可中断)