进程的组成:
• 进程控制块( PCB ):进程描述信息、进程控制、管理信息、资源分配清单和 处理机相关信息
• 程序段:能被调度程序调度到 CPU 执⾏的程序代码段
• 数据段:原始数据和执⾏过程中产⽣的数据
为了减少程序在并发执⾏时所付出的时空开销,提供操作系统的并发性能,⽽引⼊ 线程
线程由
• 线程 ID 、
• 程序计数器、
• 寄存器集合
• 堆栈组成
线程是进程中的⼀个实体,是被系统独⽴调度和分派的基本单位,线程⾃⼰不拥有 系统资源,只拥有⼀点在运⾏中必不可少的资源, 但它可与同属于⼀个进程的其他线程共享进程所拥有的全部资源
进程和线程的区别:
1. 调度
2. 拥有资源
3. 并发性
4. 系统开销
5. 地址空间
6. 通信
内核用进程组标识号(pgid)来标识一组相关的进程,这组进程对于某些事件会收到相同的信号
Wait如何处理僵尸进程
1. 取任一僵尸子进程
2. 将子进程的 CPU 使用量加到父进程
3. 释放子进程的进程表项
4. Return (子进程标识号,子进程退出码);
内核需要存储每个进程的PCB信息, linux内核是支持不同体系的的, 但是不同的体系结构可能进程需要存储的信息不尽相同,
这就需要我们实现一种通用的方式, 我们将体系结构相关的部分和无关的部门进行分离,用一种通用的方式来描述进程, 这就是struct task_struct, 而thread_info就保存了特定体系结构的汇编代码段需要访问的那部分进程的数据,我们在thread_info中嵌入指向task_struct的指针, 则我们可以很方便的通过thread_info来查找task_struct
一个进程从代码到二进制到运行时的过程图
创建进程和创建线程在用户态和内核态的不同
创建进程和创建线程在用户态和内核态的不同。
在 Linux 内核中,进程和线程都是⽤ task_struct 结构体表示的,区别在于线程的 task_struct 结构体⾥部 分资源是共享了进程已创建的资源,⽐如内存地址空间、代码段、⽂件描述符等,所以 Linux 中的线程也 被称为轻量级进程,因为线程的 task_struct 相⽐进程的 task_struct 承载的 资源⽐较少,因此以「轻」得 名。
进程管理 task_struct 的结构图
进程管理 task_struct 的结构图
structtask_struct{unsignedlongstate;intprio;unsignedlongpolicy;structtask_struct*parent;structlist_headtasks;pid_tpid;…};structthread_info{structtask_struct*task;structexec_domain*exec_domain;___u32flags;___u32status;};
进程:一段可执行的程序代码(text section),打开的文件,挂起的信号,内核内部数据,处理机状态,一个或多个具有内存映射的内存地址空间及一个或多个执行线程(thread of execution),全局变量的数据段等。
线程:是进程中活动的对象,每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。内核调度的对象是线程,而不是进程。
对Linux而言,进程只不过是一种特殊的线程罢了?
现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存;而虚拟内存让进程在分配和管理内存时觉得自己拥有整个系统的所有内存资源。
调用fork的进程称为父进程,新产生的进程称为子进程,fork系统调用从内核返回两次,一次回到父进程,一次回到新产生的子进程。
创建新的进程都是为了立即执行新的,不同的程序,而接着调用exec这组函数就可以创建新的地址空间,并把新的程序载入其中。
进程的另一个名字是任务(task)
关于时间,一个进程从创建到终止叫做该进程的生存期,进程在其生存期内使用CPU时间,内核都需要进行记录,进程耗费的时间分为两部分,一部分是用户模式下耗费的时间,一部分是在系统模式下耗费的时间.
cputime_t utime, stime, utimescaled, stimescaled;
cputime_t gtime; cputime_t prev_utime, prev_stime;//记录当前的运行时间(用户态和内核态)
unsigned long nvcsw, nivcsw; //自愿/非自愿上下文切换计数
struct timespec start_time; //进程的开始执行时间
struct timespec real_start_time; //进程真正的开始执行时间
struct signal_struct *signal;//指向进程信号描述符
struct sighand_struct *sighand;//指向进程信号处理程序描述符 sigset_t blocked, real_blocked;//阻塞信号的掩码
sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
struct sigpending pending;//进程上还需要处理的信号
unsigned long sas_ss_sp;//信号处理程序备用堆栈的地址
size_t sas_ss_size;//信号处理程序的堆栈的地址
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
struct signal_struct *signal;//指向进程信号描述符
struct sighand_struct *sighand;//指向进程信号处理程序描述符 sigset_t blocked, real_blocked;//阻塞信号的掩码
sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
struct sigpending pending;//进程上还需要处理的信号
unsigned long sas_ss_sp;//信号处理程序备用堆栈的地址
size_t sas_ss_size;//信号处理程序的堆栈的地址
/* filesystem information */
struct fs_struct *fs;//文件系统的信息的指针
/* open file information */
struct files_struct *files;//打开文件的信息指针
//进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR, 分时进程:SCHED_OTHER unsigned long policy;