〖 Linux 〗操作系统进程管理精讲(1)

一、操作系统对进程的管理

1.1操作系统为什么要对进程进行管理?

  • 进程:是操作系统进行资源分配和调度的基本单元。每个进程拥有独立的地址空间、内存、文件描述符等资源。操作系统通过管理进程,实现对系统资源的分配和调度。

  • 线程:是操作系统(特别是针对 CPU)进行调度的基本单元。线程是进程中的一个执行单元,多个线程可以共享进程的资源,但它们各自拥有独立的执行堆栈和程序计数器。线程的调度可以提高程序的并发执行能力,使程序能够更高效地利用多核处理器。

在大多数操作系统中,每个进程至少包含一个线程,即主线程。现代操作系统通常将线程作为调度的基本单元,通过管理线程来实现更精细的资源调度和更高效的并发执行。

1.2操作系统如何对进程进行管理?

  操作系统通过以下两个行为完成对进程的管理:

  • 描述进程

    • 操作系统将进程的各类关键属性(例如进程ID、父进程ID、进程状态以及进程优先级等)整合为一个结构体。这种做法类似于将学生的各项信息(例如姓名、性别、学号、班级、年龄和成绩等)组合成一个结构体来描述学生。
  • 组织进程

    • 操作系统依据进程的各类属性来组织进程运行。就像组织班级野炊时,按同学特长分组完成不同任务一样,操作系统组织进程完成用户任务也是如此。

注意:操作系统管理的只是进程的属性,通过对进程属性结构的增删查改来管理进程,而非直接管理每个进程本身的行为。


二、进程

2.1进程的概念

  进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。

  • 在早期面向进程设计的计算机结构中,进程是程序的基本执行实体,如正在执行的程序。
  • 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。

2.2进程的描述——PCB(Process Control Block)

  进程信息被放在一个叫做进程控制块(PCB)的数据结构中,可以理解为进程属性的集合。在Linux操作系统下,PCB是task_struct

  • Linux下的PCB——task_struct

    • 在Linux中,描述进程的结构体叫做task_structtask_struct是Linux内核的一种数据结构,会被装载到RAM(内存)里,并且包含着进程的信息。task_struct非常大,感兴趣的朋友可以查看它的源码: task_struct英文源码原文.
  • task_struct内容分类

    • 标示符:描述本进程的唯一标示符,用来区别其他进程。
    • 状态:任务状态,退出代码,退出信号等。
    • 优先级:相对于其他进程的优先级。
    • 程序计数器:程序中即将被执行的下一条指令的地址。
    • 内存指针:包括程序代码和进程相关数据的指针,以及与其他进程共享的内存块的指针。
    • 上下文数据:进程执行时处理器的寄存器中的数据。
    • I/O状态信息:包括显示的I/O请求、分配给进程的I/O设备和被进程使用的文件列表。
    • 记账信息:可能包括处理器时间总和、使用的时钟数总和、时间限制、记账号等。
    • 其他信息

三、进程管理

3.1组织进程

在Linux内核中,最基本的方式是采用双向链表组织task_struct。但实际上,Linux内核中组织进程的方式可能更为复杂,通常是多种数据结构的嵌套

3.2查看进程

如下代码,我们先在Linux中创建一个进程(程序)

#include<stdio.h>
#include<unistd.h>
int main()
{    
    while(1)
    {
        printf("进程正在运行中...\n");
        sleep(1);
    }
    return 0;
}

&然后用gcc编译运行这个程序:

在这里插入图片描述

可以看到进程正在每隔一秒打印一次提示信息,然后我们在另一个终端使用ps命令查看一下这个进程信息:

使用ps命令

ps ajx | head -1 && ps ajx | grep progress  //查看mypro相关的进程
//或
ps ajx | head -1 ; ps ajx | grep progress  //查看mypro相关的进程

在这里插入图片描述

查看/proc目录

ls /proc  // 查看当前系统的所有进程

在这里插入图片描述

查看具体进程目录

ls /proc/23329 -l

在这里插入图片描述

使用top命令

top

在这里插入图片描述

通过系统调用获取进程标识符

可以通过getpid()getppid()获取进程ID和父进程ID。

  • 进程id(PID)
  • 父进程id(PPID)

在这里插入图片描述
   可以通过getpid(),getppid()来获取进程id和父进程id,函数手册如下:

在这里插入图片描述

3.3示例代码

   我们编写一个进程,然后调用getpid()和getppid()函数来获取它的进程id和父进程id,代码如下:

#include <stdio.h>
#include <unistd.h>
int main() 
{
	while(1) 
	{
		printf("进程正在运行中...\n");
		printf("进程ID: %d\n", getpid());
    	printf("父进程ID: %d\n", getppid());
		sleep(1);
	}
	return 0;
}

   使用gcc编译运行,再在另一个窗口查询进程相关信息:
在这里插入图片描述


四、创建进程

4.1fork()函数

  我们前面尝试了在指令级别运行一个进程,即运行我们写的程序; 现在我们来看一下在代码层面如何创建一个进程。
  先来看一下Linux的fork()函数手册:在这里插入图片描述
在这里插入图片描述

4.2 示例代码

  我们通过一段代码来观察一下fork()函数调用的现象,代码如下:

#include <stdio.h>
#include <unistd.h>

int main() {
    printf("运行fork函数前\n");
	fork();
    printf("运行fork函数后\n");
	sleep(1);
    return 0;
}

  编译运行代码,结果如下
在这里插入图片描述
  可以看到, fork()函数后的代码竟然被打印了两遍! 这是因为我们在调用fork()函数之前程序只有一个执行流,而调用fork()函数之后程序就开始有两个执行流了,所以两个执行流都执行了打印操作,我们的屏幕上才会看到两个打印的结果。

在这里插入图片描述

4.3fork()函数的两个返回值

  fork()函数返回两个值:

  • 父进程返回子进程的PID。
  • 子进程返回0。
  • 如果创建失败,返回-1,并适当设置errno报错.

在这里插入图片描述

4.4示例代码

  下面我们测试一下接收fork()函数的返回值,代码如下:

#include <stdio.h>
#include <unistd.h>

int main() {
    printf("运行fork() 函数前\n");
	pid_t id = fork();
	
	if (id == 0){
		while (1) {
			printf("运行fork()函数后的子进程, pid : %d, ppid : %d\n", getpid(), getppid());
			sleep(1);
		}
	} 
	else if (id > 0) 
	{
		while (1)
		{
			printf("运行fork()函数后的父进程, pid : %d, ppid : %d\n", getpid(), getppid());
			sleep(1);
		}
	} 
	else 
	{
		printf("fork()函数开辟进程失败!\n");
	}
	return 0;
}

在这里插入图片描述
  在测试中,子进程和父进程分别执行了不同的代码逻辑。虽然从输出结果来看,似乎父进程的信息先被打印出来,这可能是因为在本次测试中,fork() 函数优先执行了父进程的代码。然而,实际上,父子进程的执行顺序是由操作系统的调度器决定的,不同的系统、不同的进程或在不同的时间进行测试,结果可能会有所不同,因此父子进程的执行顺序是不确定的。

  通过实验,我们发现 fork() 函数确实创建了一个新的进程。只有当两个进程并行运行时,代码才能打印出两个 if 语句分支的循环结果。如果按照单进程的逻辑执行,程序一旦进入其中一个死循环,就无法退出,因此我们只能看到其中一个死循环的输出。而在这次实验中,我们观察到了两个分支的输出,这进一步验证了 fork() 创建了两个独立的进程,并且它们在并发执行。


在这里插入图片描述

4.5 进一步探究fork()函数

  关于fork()函数,有几个问题需要解答一下:

    1. 为什么fork()函数要给子进程返回0,给父进程返回子进程PID?
    • 区分执行流:设置父子进程不同返回值,使fork()后父子进程能通过 if 判断执行不同代码块。
    • 代码共享注意项:fork()后的代码由父子进程共享,需通过返回值区分执行逻辑。
    • 子进程管理:父进程获子进程PID,便于管理多个子进程,通过记录各PID实现精准管控。
    1. fork()函数究竟做了什么?
    • 创建子进程的PCB
    • 填充PCB的内容。
    • 让子进程和父进程指向相同的代码。
    • 父子进程都有独立的task_struct,可以被CPU调度运行
    • …(fork()函数的主要工作完成之后,后面的代码就是父子共享的了!)
    • return id ; (因为这里的fork()函数的return 语句已经在成功创建子进程后了,这意味着从那之后父子进程就会分别拥有一个return 语句,这样就可以做到父进程返回一个值,子进程返回一个值了)
    1. 一个函数是如何做到返回两次的?
    • 子进程创建后,后面的代码是共享的,因此return语句被父子进程共享,从而实现返回两次的效果。
    1. 一个变量怎么会存有不同的内容?
    • 父子进程的代码共享,但数据采用写时拷贝,因此数据互不干扰,可以存不同的内容。
    • 即实际上这个变量已经不是一个变量了,而是父进程的变量和写时拷贝出的子进程变量这两个变量,因此可以存不同的内容。


      在这里插入图片描述

  这样安排的主要原因是进程间相互具有独立性, 进程代码因为不会被进程更改,所以父子共享是没问题的,但进程数据是可能被进程更改的,如果父子进程间可以互相影响数据,那么就很容易导致出错的情况。
  这类似于父子共用一个书房:共享书籍(代码)不会损坏书籍,但笔记本(数据)需各自独立使用,避免因一方记录不当影响另一方的学习和工作。

五、进程状态

5.1操作系统层面的进程状态

 &emsp;&emsp;进程状态反映进程执行过程的变化。这些状态随着进程的执行和外界条件的变化而转换。常见的模型包括三态模型(运行态、就绪态、阻塞态)和五态模型(新建态、就绪态、运行态、阻塞态、终止态)。

进程状态

新建状态 (New):

  进程刚被创建,PCB(进程控制块)和对应的代码、数据已分配,但尚未投入运行。

就绪状态 (Ready):

  进程已准备好运行,正在等待CPU资源。处于就绪状态的进程在运行队列中排队,等待调度器调度。

运行状态 (Running):

  进程正在CPU上执行。在单CPU系统中,同一时间只有一个进程处于运行状态。

阻塞状态 (Blocked):

  进程因等待某个事件(如I/O操作完成)而无法继续执行。阻塞状态分为两种:

  • 浅度睡眠 (Interruptible Sleep):
    • 等待外设资源,可以被操作系统信号唤醒。
  • 深度睡眠 (Uninterruptible Sleep):
    • 等待磁盘资源,不能被操作系统信号唤醒。
终止状态 (Terminated):

  进程已执行完毕,或因错误被终止,资源被释放。

挂起状态 (Suspended):

  进程被暂时移出内存,代码和数据被交换到磁盘上的swap分区,以节省内存资源。挂起状态的进程在需要时可以被重新调入内存继续执行。

5.2 Linux系统层面的进程状态

  Linux内核中定义的进程状态如下:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

在这里插入图片描述

R: 运行状态

  • 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。

  但是要注意,我们查看进程时,不能只根据表面来推测判断它处于什么状态,而应该更严谨的去分析进程的行为再做判定。

  比如,我们创建一个程序,代码如下:

#include <stdio.h>
#include <unistd.h>

int main() 
{
	while(1) 
	{
		printf("进程正在运行中...\n");
		sleep(1);
	}
	return 0;
}

  然后我们运行进程,查询该进程的状态:
在这里插入图片描述

  可以发现明明左边进程一直在运行,但是右边查询进程属性的结果却显示进程在等待状态。这是因为我们在进程中调用了printf()函数,即调用了硬件设备显示器来向屏幕上打印内容,而当硬件显示器在打印内容时,进程就是处于等待硬件工作的状态的, 并且硬件显示器向屏幕打印的时间相对CPU运行时间来说很慢,两者是数量级的差别,硬件几乎占了99.99%的时间,所以我们在查询进程状态时,大部分时间查到的都是进程在等待打印的时候。

#include <stdio.h>
#include <unistd.h>

int main() 
{
	while(1) 
	{
	}
	return 0;
}

  可以看到,进程当前处于R运行状态:在这里插入图片描述
注意:

  • 带+的状态表示是在前台运行的进程,如果我们在运行进程指令后面加一个 & ,那么进程就会在后台运行,状态后面就不会有+号。(杀后台进程用kill -9 [pid]来完成)

  当我们将while循环中的打印语句删除,再运行,查询进程状态:

S: 睡眠状态

  • 进意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断(浅度)睡眠(interruptible sleep))。浅度睡眠状态意味着该进程当前是可以相应操作系统的操作的,比如可以直接被操作系统杀死。

D: 磁盘休眠状态

  • ;有时候也叫不可中断(深度)睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。并且该进程不会响应任何操作系统的请求, 即操作系统无法将其杀死或者是进行其他任何操作。这样做主要是为了防止操作系统将某些重要的正处于等待状态的进程误杀。

T: 停止状态

  • 可以通过发送SIGSTOP信号停止进程,通过发送SIGCONT信号让进程继续运行。

  可以通过给进程发kill -18/19 [pid]来使进程恢复运行/暂停.
   T状态和S状态的区别是:两者都可以是为了等待某种资源而暂停,但T状态更为自由一些,它也可以不是因为等某种硬件资源,而是单纯的就是不想进程再运行,所以就可以将进程暂停。。

t: 追踪停止状态

  在GDB中,如果你看到进程状态为t,这通常表示进程处于追踪停止(tracing stop)状态。这可能是因为进程接收到SIGTRAP信号,通常用于调试目的,比如断点触发。

Z: 僵死状态

  • 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用**wait()**系统调用,后面讲)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程
  • 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码。
  • 所以,只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程就会进入Z状态
  • 处于僵死状态的进程就被成为僵尸进程,其相关资源尤其是task_struct结构体不能被释放,这也就会导致僵尸进程会一直占用内存资源!

  一个进程在退出之后并不是就要立即将自己的所有资源全部释放, 而是操作系统要将该进程的退出信息维持一段时间, 直到该退出进程的相关进程知道了该进程退出的相关信息和原因之后,才会释放该进程的相关信息和资源。从进程退出,到相关进程接收到退出信息之间的这一段状态,就成为进程的僵死状态。

  我们通过一段代码演示一下僵死状态,我们用fork()创建一个子进程,然后让它休眠3秒之后直接退出,同时我们让父进程休眠30秒,这样在子进程退出后由于父进程处于休眠状态就没法立即回收子进程的信息,子进程就会进入僵死状态,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
	pid_t id = fork();

	if(id < 0) // fork() 失败
	{
		perror("fork error!\n");
		return 1;
	}
	else if(id > 0) // 父进程
	{
		printf("父进程:%d正在休眠...\n",getpid());
		sleep(30);
	}
	else // 子进程
	{
		printf("子进程:%d 正在休眠...\n",getpid());
		sleep(3);
		exit(0);
	}
	return 0;
}

  然后我们编译运行程序,调出监控窗口查看进程状态, 监控命令如下:

while :; do ps axj | head -1 && ps axj | grep progress;sleep 1; echo "----------------------------------------------";done

查看结果,可以看到子进程确实从第三秒后就变成了僵死状态,名字后面也被标上了:

在这里插入图片描述
僵尸进程的危害:

  • 无人回收时进程的退出状态必须被维持下去,因为他要告诉和它相关的进程(父进程),你交给我的任务,我完成的怎么样,又或是遇到了怎样的状况。父进程如果一直不读取子进程的退出信息,那子进程就会一直处于Z状态!
  • 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,如果Z状态一直不退出,PCB就一直都要维护
  • 如果一个父进程创建了很多子进程,但是不回收,就会造成内存资源的浪费!因为数据结构对象本身就要占用内存,要在内存的某个位置进行开辟空间,这就会导致内存泄漏!

孤儿进程

  我们刚刚讨论的是子进程比父进程先死亡的情况,但还有一种可能的情况是父进程比子进程先死亡,这种子进程就被成为孤儿进程,该进程会被1号进程(即操作系统)领养,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main() {
	pid_t id = fork();

	if(id < 0) // fork() 失败
	{
		perror("fork error!\n");
		return 1;
	}
	else if(id > 0) // 父进程
	{
		printf("父进程:%d正在休眠...\n",getpid());
		sleep(3);
	}
	else // 子进程
	{
		printf("子进程:%d 正在休眠...\n",getpid());
		sleep(30);
		exit(0);
	}
	return 0;
}

  编译运行,调用监控查看结果:
在这里插入图片描述
  所以父进程是1号进程(操作系统)的进程就被称为孤儿进程.操作系统领养孤儿进程的主要目的是为了后续回收孤儿进程的退出信息并将其释放,防止存在内存泄漏问题。

X: 死亡状态

  • 该状态只是一个返回状态,不会出现在任务列表中。

5.3运行队列和调度

  运行队列:每个CPU维护一个运行队列,其中包含所有就绪状态的进程。调度器从运行队列中选择进程执行。

调度器
  • 负责在运行队列中选择进程投入CPU运行,确保CPU资源的合理利用。
阻塞和挂起
  • 阻塞:进程等待某个事件(如I/O操作完成)时进入阻塞状态。阻塞状态的进程不占用CPU资源。
  • 挂起:当系统内存资源不足时,操作系统可能将某些不活动的进程挂起,将其代码和数据交换到磁盘上的swap分区,以释放内存。

六、进程优先级

6.1 基本概念

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能( 但前提是能够客观公平的设置,一般情况下还是遵守调度器的调度,不要擅自修改进程优先级 )。
  • 还可以把进程运行到指定的CPU上, 把不重要的进程安排到某个CPU,可以大大改善系统整体性能。

6.2 PRI和NI的概念

  我们在linux或者unix系统中,用ps –l命令会输出以下几个内容::

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI:进程的优先级,值越小优先级越高。
  • NI:nice值,表示进程优先级的修正数值。
    • PRI的新值 = PRI的旧值 + nice值。
    • nice值的范围是-20到19,值越小优先级越高。
  • 需要强调的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。nice值是进程优先级修正的修正数据

6.3查看/修改进程优先级

  • 查看优先级:使用pstop命令。

    • 使用ps命令查看进程PRI值和NI值:
      在这里插入图片描述
    • 使用top命令查看已存在进程的nice值:
      在这里插入图片描述
    • 使用 top 命令 :在终端中输入 “top” 命令,按下回车键后,会显示系统中所有进程的详细信息,其中第 “PR” 列表示进程的优先级。数值越小,优先级越高。同时,可以通过 “u” 参数指定用户,如 “top -u username”,查看特定用户的进程优先级。
  • 修改优先级:使用top命令,进入后按“r”->输入进程PID->输入nice值。

    • 注意:普通用户不能修改nice值,只有root用户可以。
  • 使用 nice 命令启动进程
    语法 :nice -n <优先级> <进程命令>
    说明 :-n 后跟要设置的 nice 值,范围通常是 -20 到 19,数值越小,优先级越高。<进程命令> 是要启动的进程的命令。
    示例 :nice -n -5 firefox,以 nice 值为 -5 启动 firefox 浏览器。

  • 使用 renice 命令修改正在运行的进程的 nice 值
    语法 :renice -n <新的优先级> -p <进程 ID>
    说明 :-n 指定要设置的新 nice 值,-p 后跟要修改的进程的 ID。
    示例 :renice -n -10 -p 1234,将进程 ID 为 1234 的进程的 nice 值修改为 -10。


7.四个重要概念

  1. 竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级
  2.独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
  3.并行:多个进程在多个CPU下分别,同时进行运行,这称之为并行
  4.并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

下面具体解释并发:

  • 多个进程在你的系统中运行 != 多个进程在你的系统中同时运行
  • 进程不是占用了cpu,就会一直执行到结束然后释放cpu资源,我们遇到的大部分操作系统都是分时的!所谓的分时就是操作系统会给每一个进程,在以此调度周期中,赋予一个时间片的概念。
    在这里插入图片描述
  • 如图:假设进程1进入cpu运行,假设操作系统给它分配10ms的时间,如果10ms到了,无论结果如何都不会再让你进程1继续运行了,操作系统会把你进程1从cpu上剥离下来,然后再调度进程2……假设往后每个进程都是分配10ms,1s = 1000ms,那么在1s内,这5个进程平均每个都要调度20次。

  总结:在一个时间段内,多个进程都会通过切换交叉的方式,让多个进程代码,在一段时间内都得到推进,这种现象,我们叫并发。

补充1抢占式内核

  • 我们的操作系统内部支持抢占式内核,正在运行的低优先级进程,但如果来个优先级更高的进程,我们的调度器会直接把进程从cpu上玻璃,放上优先级更高的进程,这就是进程抢占。

补充2进程的 优先级 | 队列

  • 操作系统内是允许不同的优先级的存在的,且相同优先级的进程,是可以存在多个的。但是进程是一个先进先出的队列,如果在原有稳定的进程基础上,突然来了一个优先级更高的进程,那它就会随便插队吗,这不就不符合队列的性质了。这里就可以借用指针数组、hash来解决:

总结:linux内核是根据不同的优先级,将特定的进程放入不同的队列中,而cpu就很自然的从数组的优先级最高的地方开始寻找进程。 在这里插入图片描述
补充3:运行队列与等待队列
在这里插入图片描述
当运行队列中的进程按顺序(从上到下、从左到右)运行结束后,运行队列和等待队列的指针会进行交换,使得等待队列中的进程成为新的运行队列,而原运行队列变为空。

重点

  • 当运行队列中的进程全部运行结束(队列为空),等待队列会接管 CPU。
  • 原运行队列的指针指向原等待队列,原等待队列的指针变为空。
  • 这种机制常用于多任务调度,以实现进程的轮流运行。

补充4进程间是如何进行切换的。

  • cpu内部存在各种各样的寄存器,可以临时的保存数据。而寄存器又分可见寄存器和不可见寄存器。当进程在被执行的时候,一定会存在大量的临时数据,会暂存在cpu内的寄存器中。当你要把下一个进程放上来的时候,除了要把上一个进程拿走,还要把你的历史数据拿走,示例:
  • 假如小王刚上大一,还没开学,随即填报了大学生征兵入伍,为了保留学籍,小王向学校申请了保留学籍,此时学校要留存小王的数据(个人信息,学籍……)。小王两年义务兵退伍后,随即又向学校申请恢复学籍,此时小王就可以从先前被切走的地方(大一)继续运行(上学)。此时学校扮演的角色就是cpu,小王在学校产生的所有临时数据就是上下文数据,小王就是一个进程,小王当兵被招走就相等于被操作系统切换下去,前提是在cpu内把临时数据保存好,为了的是后续的恢复。

  总结:我们把进程在运行中产生的各种寄存器数据,我们叫做进程的硬件上下文,

  • 当进程被剥离:需要保存上下文数据(task_struct)。
  • 当进程恢复的时候:需要将曾经保存的上下文数据恢复到寄存器中
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值