基于linux操作系统的内核进程管理子系统

内核进程管理子系统
4.1 概述
WOS 是支持多进程的操作系统内核。这就意味着,各个用户进程在运行过程中,彼此不能相互干扰,这样才能保证进程在主机中正常地运行。在某个 CPU 上,某一时刻,处 理器只会执行一个任务。程序是静态的、存储在文件系统上、尚未运行的指令代码;进程则是指正在运行的程序,即进行中的程序。一个进程的指令地址所组成的执行轨迹称为控制执行流。进程的执行流是独立的,互不干扰的。为了保证每个进程执行流的独立性,每个进程的运行必须获得运行所需要的各类资源,这些资源包括进程所使用的栈、一套自己的寄存器映像和内存资源等。操作系统为每个进程提供一个 PCB,即进程控制块,记录、描述和管理程序执行的动态变化过程,它就是进程的身份证,用它来记录与进程相关的信息,比如进程状态、PID 等。另外,在中断到来或发生进程切换时,必须(也只需要)把进程的寄存器组信息完整地保存下来。在 Linux 内核中,通常由 task_struct 结构描述。每个进程都有自己的 PCB,所有 PCB 放到一张表中维护,这就是进程表,PCB 就成为进程表中的“项”,因此 PCB 又可称为进程表项。另外进程 PCB 没有具体格式, 其实际格式取决于操作系统的功能复杂度。
进程从执行到结束的整个过程中,并不是所有阶段都一直开足马力在处理器上运行,有 时也会由于某些原因不得不停下来。为此,通常把进程“执行过程”中所经历的阶段按状态进行分类。进程有哪些状态,取决于操作系统对进程的管理办法,当一个进程在执行时,CPU 的所有寄存器中的值、进程的状态以及堆栈中的内容被称为该进程的上下文。当内核需要切换(switch)至另一个进程时,它就需要保存当前进程的所有状态,即保存当前线程的上下文,以便在再次执行该进程时,能够恢复到切换的状态执行下去。
4.2 实验项目
4.2.1 进程创建
1.实验目的
(1)理解进程的本质;
(2)理解进程控制块及其管理方法;
(3)掌握模拟器的基本使用方法和调试方法。
2. 实验准备
操作系统为每个进程管理一个 PCB。在 Linux 内核中,通常定义task_struct 结构描述。其实,进程 PCB 没有具体格式,其实际格式取决于操作系统的功能复杂度。
所谓创建进程,其实是初始化进程控制块各项。
一个进程开始之前,只要指定各段寄存器、eip、esp 和 eflags,就可以正常运行了,至于其他寄存器是用不到的,所以,在创建进程体时,必须初始化的寄存器列表为:cs、ds、es、fs、esp、eip 和 eflags。其中,cs、ds 等段寄存器对应的是 GDT 中的描述符,每个进程都有自己的 PCB,系统通过进程表来管理所有进程。进程表的组织形式比较灵活。其中在 Linux 系统中,进程表定义成进程队列数组的形式,例如 struct task_struct *task[NR_TASKS]; 规定系统可同时运行的最大进程数(见 kernel/sched.c);每个进程占一个数组元素。可以通过 task[]数组遍历所有进程的 PCB。但 Linux 也提供一个宏定义for_each_task()(见 include/linux/sched.h),它通过 next_task 遍历所有进程的 PCB。在 WOS 源代码的 include/adt/list.h 文件中,采用了一种(数据结构)类型无关的双循环链表实现方式。其思想是将指针 prev 和 next 从具体的数据结构中提取处理构成一种通用的 “双链表”数据结构 list_head,而 list_head 被作为一个成员嵌入到要拉链的数据结构(被称为宿主数据结构)中。这样,只需要一套通用的链表操作函数就可以将 list_head 成员作为“连接件”,把宿主数据结构链接起来。
就绪队列
3. 实验方案
在本实验中,WOS 进程控制块 PCB 主要包括以下几个部分:
①进程标识符,主要 pid;
②处理机状态信息:通用寄存器、指令计数器、程序状态字、用户栈指针;
③进程调度信息:进程状态、优先级等;
④进程控制信息:程序和数据的地址、同步和通信机制、资源清单、链接指针等;
由于,本节实验是在内核空间,创建内核进程,实现基本的进程管理及切换,因此 PCB不包含用户进程需要的资源记录,同时关于调度、通信、同步等信息会在后面实验中陆续添加。


enum proc_state{UNUSED=0,RUNNABLE,RUNNING,BLOCKED,STOPED};
struct task_struct
{
       TrapFrame *tf;
       char kstack[KSTACKSIZE];
       pid_t pid;
       char pname[20];
       enum proc_state state;
       int  delay;
       int number;
       int nice;
       ListHead linklist;
}task_struct  ;
//其中,TrapFrame 结构用于定义系统寄存器信息,定义在 include/x86.h 中。
struct TrapFrame { 
uint32_t edi, esi, ebp, esp_; 
uint32_t ebx, edx, ecx, eax; // Register saved by pushal 
uint32_t gs, fs, es, ds; // Segment register 
int irq; // # of irq
uint32_t err, eip, cs, eflags; // Execution state before trap 
uint32_t esp, ss; // Used only when returning to DPL=3 

}; 
typedef struct TrapFrame TrapFrame; 

为了管理系统中的所有进程控制块,系统还要维护如下全局变量与进程 PCB 相关的几个数据结构

#define NR_PROC 64
struct task_struct task[NR_PROC];
extern  struct task_struct * current;  /指向当前工作进程
ListHead *RunableList;           //指向就绪队列的指针,便于使用list.h中的内联函数

说明 task_list是进程管理队列,可以根据系统需求创建多种队列,例如就绪队列、阻塞队列等等;在这里,task[]是进程表,NR_TASKS 定义了最大允许进程;current 表示当前占用 CPU且处于“运行”状态进程控制块指针。通常这个变量是只读的,只有在进程切换的时候才进行修改,并且整个切换和修改过程需要保证原子操作;RunableList 是用于管理就绪进程的双向循环列表结构,task_struct 中的成员变量 linklist 将链接入这个链表中(链表结构LishHead的定义在 include/adt/list.h 中)。

操作系统通过进程表来管理所有进程 PCB,task[]数组大小固定,因此系统中的进程是受限资源,即系统的最大进程数量是有限的。进程创建的本质就是为进程分配 PCB,并设置为就绪状态。在 WOS 操作系统中,为了实现进程管理需要进行如下操作:
A. task_init:task 进程表初始化
B. idle_init: 创建 0 号进程
C. kthread_create:进程创建
4-1 进程表初始化

struct task_struct* init_pcb1(struct task_struct * p,void (* proc)(void),const char *name );
extern int nextpid;
extern int ticks;
void task_init()
{
    int i=0;
    for(;i<NR_PROC;i++)
    {
       task[i].state=UNUSED;
    }
}

4-2 创建 0 号进程

void idle_init()
{   
    struct task_struct * p;
    task[0].state=RUNNING;
    p=&task[0];
    p=init_pcb1(p,idle_init,"idle");
    current=p;
    list_init(&RUNABLELIST);   
    RunableList=&RUNABLELIST;
    printk("0 init ok\n");
}

4-3 进程创建

void creat_kthread(void (*proc)(void),const char *name )
{    
    struct task_struct * pp=NULL;
     pp=&task[nextpid];
    int i=0;
    for(;i<NR_PROC;i++)
    {
       if(task[i].state==UNUSED)
         {  pp=&task[i];
             break;
         }
    }
    pp=init_pcb1(pp,*proc,name);
     printk("%d",pp);
     printk("%s",pp->pname ,"is inited\n");
     printk("%s","pid = ");
     printk("%d\n",pp->pid);
}

4-4 初始化 PCB

struct task_struct* init_pcb1(struct task_struct * p,void (* proc)(void),const char *name )
{
    TrapFrame *tf;
    p->pid=nextpid++;
    p->state=RUNNABLE;
    tf=(TrapFrame*)(memset(p->kstack,0,KSTACKSIZE)+KSTACKSIZE)-1; //初始寄存器组
p->tf=tf;
tf->eflags=(uint32_t)(0x01<<9);
tf->cs=(uint32_t)KSEL(SEG_KCODE);
tf->ds=(uint32_t)KSEL(SEG_KDATA);
tf->gs=(uint32_t)KSEL(SEG_KDATA);
tf->eip=(uint32_t)*proc;
tf->esp=(uint32_t)tf;
tf->irq=0x03e8;
memcpy(p->pname,name,7); //设置进程名字
p->nice=15;
p->number=15;
p->delay=0;
list_init(&p->linklist);
if(nextpid>1)
list_add_after(RunableList,&p->linklist);
return p;
}

4.实验验证及分析
测试程序如下

#include "sched.h" 
#include "debug.h" 
void  a(){ 
while(1){ 
printk("A"); 
wait_intr(); 
} } 
void  b(){ 
while(1){ 
printk("B"); 
wait_intr();
} } 
void  c(){ 
for(i=1; i<=10; i++){ 
printk("C"); 
wait_intr(); 
} } 
void  test_proc(){ 
create_kthread(a, "A_proc"); 
create_kthread(c, "B_proc"); 
create_kthread(b, "C_proc"); 
} 

进程创建
由实验结果看出单操作系统经过引导初始化后,创建的第一个程序为“0”号进程,接着创建了三个进程,分别打印出了PCB地址,进程名,进程的pid。

4.2.2 进程切换

  1. 实验目的
    (1)了解系统中断机制;
    (2)理解进程切换本质;
    (3)掌握模拟器的基本使用方法和调试方法。
  2. 实验准备
    操作系统是由“中断驱动”的。中断是现代操作系统实现并行性的基础之一。引入中断机制,操作系统在让应用程序放弃控制权或从应用程序获得控制权将具有更大的灵活性。因此,操作系统中进程的切换也是以中断为基础的。当中断发生时,当前进程放弃处理器,新进程获得处理器开始执行。可以这样讲,进程上下文的切换都是由中断事件引起的。
    为了完成本小节关于进程切换的操作,首先了解当前系统中的中断机制实现情况。本节系统中涉及到的中断为“硬中断”,包括中断(又称外中断或异常中断)和异常(又称内中断或同步中断)。中断机制设置“中断描述符表”,以向量号为索引查找中断向量,然后转入中断处理程序或异常处理程序。在保护模式下,系统采用中断描述符表(Interrupt Descriptor Table,IDT),此表可以包含 256 个中断描述符,与中断或异常一一对应。描述符的作用是把程序控制权转给中断异常服务程序,每个描述符结构如图 所示,均占 8 个字节,通过它就能找到服务程序的起始地址、属性以及程序特权级别等。IDT 的位置由硬件中断描述符寄存器 IDTR 指定,它是一个 48 位的寄存器,高 32 位的 IDT 基址,低 16 位限定 IDT的长度。
    由此可见,中断和异常是激活操作系统的方法,它暂停当前运行进程的执行,把处理器切换至核心态,内核获得处理器的控制权之后,如果需要就可以实现进程切换。内核在处理中断事件或系统调用或者在处理时钟中断事件期间发现运行进程的时间片耗尽等,都可能引发内核实施进程上下文切换。
    假设,当中断发生时,进程让出处理器时,寄存器上下文将被保存到系统级上下文的相应的现场信息位置,这是内核就把这些信息压入核心栈;当内核处理完中断返回时,内核进行上下文切换,并从核心栈中弹出上下文。
  3. 实验方案
    (1) 中断机制的实现
    在系统初始化阶段,创建 IDT。每个中断/异常均有其相应的处理程序,在使用中断之 前,必须在 IDT 中注册以保证发生中断时能找到相应的中断处理程序。以 32 号时钟中断为例。 首先,在 IDT 中定义时钟中断描述符,代码如下所示,
idt[32] = GATE(STS_IG32, KSEL(SEG_KCODE), irq0, DPL_KERN); 

定义 irq0 即中断处理程序,

.globl irq0; 
irq0: 
pushl $0; //错误码 
pushl $1000; //时钟中断号=1000 
jmp trap // 
.extern irq_handle 
trap: 
cli 
pushl %ds //入栈,段寄存器 ds、es、fs、gs 
pushl %es 
pushl %fs 
pushl %gs 
pushal //入栈,4 个通用寄存器(eax、ebx、ecx、edx) 
//2 个指针寄存器(esp、ebp) 
//2 个变址寄存器(esi、edi) 
movw $KSEL(SEG_KDATA), %ax //设置 ds、es 
movw %ax, %ds 
movw %ax, %es 
pushl %esp //栈顶指针寄存器入栈
call irq_handle //中断处理程序 

 movl (current),%esi
  movl (%esi),%esppopal 

popl %gs 
popl %fs 
popl %es 
popl %ds 
addl $8, %esp 
iret //恢复 cs、eip、eflags 在这里插入代码片

使得当中断发生时,可以保护现场并且调用irq_handle()函数,这个中断处理函数会继续调用schedule()函数选择新的进程,接着将选择的新进程的工作栈弹出。
(2) 进程切换
在实现进程切换之前,我们不妨来模拟一下进程切换的行为。当前进程正在运行时,堆栈上
的内容是与进程相关的,而 current 指针指向了当前运行进程的 PCB。这个时候,中断发生了。中断处理程序会在当前的堆栈上保存 CS, EIP 和 EFLAGS 三个寄存器,并跳转到汇编代码执行。汇编代码如同预期的,把寄存器现场(TrapFrame)保存到堆栈上,并执行 pushl %esp将栈顶指针保存下来,这下,我们进程的状态就和之前图中的状态一样了。
C 语言代码继续在堆栈上运行,可能会在堆栈中插入新的内容,但当前进程 PCB 的结构却不会发生任何变化。C 语言代码可能会执行一些如中断处理的工作,然后判断是否需要执行进程切换。如果需要执行进程切换,C 语言代码只是把 current 指针切换: current = next_process(); 然后就从 C 语言代码返回了。返回后,汇编语言执行堆栈切换,然后照例恢复寄存器现场:

popal; popl %gs; popl %fs; popl %es; popl %ds 
addl $8, %esp 
iret 

注意到此时的堆栈已经是新进程的堆栈了,在寄存器现场恢复完毕后,另一个线程就恢复执行了!
4-5 进程切换(Switching of Process)

void schedule()
{
    struct task_struct * old=NULL;
    struct task_struct * new=NULL;
    struct task_struct * temp=NULL;
new=list_entry(RunableList->next,struct task_struct,linklist); 
List_del(&new->linklist);
    RunableList=RunableList->next; 
    new->state=RUNNING; 
    list_add_before(RunableList,&old->linklist); 
    old = current;
    old->state=RUNNABLE;
     current=new;  
  }

本实验进程切换,由中断触发,执行函数调用关系:trapirq_handle()schedule()
说明 1:idle 进程(即 0 号进程)是内核进程,只有在系统空闲时运行。进程切换时总是从 Runable_list 中选择一个就绪进程作为 current 进程调度执行,当 Runable_list 为空时才会再次调度 idle 进程。
5.实验验证及分析
进程切换
测试程序如上一部分测试程序,将三个进程开始切换运行起来。

4.2.3 调度机制

  1. 实验目的
    (1) 理解操作系统的调度管理机制。
    (2) 熟悉mcore的系统调度框架,并实现基于优先级的调度算法。
  2. 实验准备
    进程调度是操作系统最为核心到部分,执行十分频繁,其调度策略的优略降直接影响整个系统的性能,因而,这部分代码要求精心设计,并常驻内存。
    内核中的调度程序用于选择系统中下一个要运行的进程。这种选择机制是多任务操作系统的基础。可以将调度程序看做在所有处于运行状态的进程之间分配 CPU 运行时间的管理代码。
    例如在 Linux 系统中通过 schedule()函数来完成调度操作,为了能让进程有效地使用系统资源,又能使进程有较快的响应时间,就需要对进程的切换调度采用一定的调度策略。在Linux0.12 中采用了基于优先级排队的调度策略。schedule()函数首先扫描 task[]任务数组。通过比较每个就绪态任务的运行时间递减滴答计数 counter 的值来确定当前哪个进程运行的时间最少。哪一个的值大,就表示运行时间还不长,于是就选中该进程,并使用任务切换宏函数切换到该进程运行。如果此时所有处于就绪态进程的时间片都已经用完,系统就会根据每个进程的优先权值 priority,对系统中所有进程(包括正在睡眠的进程)重新计算每个任务需要运行的时间片值 couner。计算的公式是: counter=counter/2+priority;这样,正在睡眠的进程被唤醒时就具有较高的时间片 counter 值。然后 schedule()函数重新扫描任务数组中所有处于就绪态的进程,并重复上述过程,直到选择出一个进程为止。
  3. 实验方案
    本实验模拟系统时钟,每次时钟到来时,使得 ticks 加 1,来统计系统时钟触发次数, 借此,为处理器调度提供时间上的辅助。 因此,对于计时器的基本操作包括:(1)初始化系统计时器;(2)定时器累加;(3)获得系统时钟值;
    4-7 初始化系统计时器
void init_ticks()
{
    ticks=0;  
}

4-8 定时器累加 `

void acc_timer()
{
    ticks++;
}

4-9 获得定时器值

int get_timer()
{
    return  ticks;
}

本实验中对操作系统时钟的实现非常简单,但是已经模拟了操作系统内核对于时钟操作 的本质。接下来需要对系统计时器进行测试,可以模拟实现 sleep()的功能,在这里称为 w_delay()来模拟实现让进程延迟睡眠功能。因为进程的PCB中记录delay数据的成员,这时当进程调用w_delay()函数时,将延时的值赋给当前进程的delay变量,接着陷入死循环采用忙等的方法直到delay延时的时间结束,跳出循环,结束延时。
4-10 延迟函数

void w_delay(int n)
{
    current->delay=n;
    while(1)
    {  
             wait_intr();
        if(current->delay==0)
        {
            break;           
    }
}

4—11中断处理函数部分代码
关于中断计时和延时及时的函数,当时间片结束后调用shedule()函数切换进程。

if(irq==1000)
        {
            /* interrupt */
           acc_timer(); 
           if(current->delay)
           {
            current->delay=  current->delay-1;
           }
           if((current->number==0) || (current->number==get_timer()))
           {    
               current->number=0; 
               schedule();      
            }
         }

进程调度是操作系统的核心之一。进程调度的时机多种多样,就目前我们实现的系统功能,进程调度一般发生在进程被动放弃 CPU,当前进程的时间片用完,或一个进程被唤醒且其优先级高于当前进程的优先级等情况。
①处理当前进程:根据调度切换原因,将当前进程加入到就绪或阻塞队列;
②选择进程运行:扫描就绪队列中的所有就绪进程,从中选择合适的进程运行,将其设为 current,并从就绪队列中移除该进程。
③进程切换:进程上下文切换。
参考 Linux0.12 设计动态优先级调度算法:优先级高的就绪进程先运行,优先级低的就绪进程后运行,优先级相同的进程按轮转方式运行。
下面的结构用来描述基于优先级的进程轮转调度算法在 mcore 中的实现方案。
在 task_struct 结构中,存放于进程调度相关的成员供调度模块使用。
int nice; //进程可控优先因子
int number; //进程目前时间片配额,也称进程动态优先级
4-12 调度算法

void schedule()
{
    struct task_struct * old=NULL;
    struct task_struct * new=NULL;
    struct task_struct * temp=NULL;
    ListHead *ptr=NULL;
    int flag=1;
    /* for(;i<=3;i++) */
list_foreach(ptr,RunableList)
    {
           temp=list_entry(ptr,struct task_struct,linklist);
           if((temp->state!=0)&&temp->number ==0)
               continue;
           else 
           {
               flag=0;
               break;
           }
           
       }
      ptr=NULL;
    if(flag)
    {
      /* for(;i<=3;i++) */
       list_foreach(ptr,RunableList)
       {
             temp=list_entry(ptr,struct task_struct,linklist);
             temp->number=temp->nice;
           
       }
    }
     if(current->state)
     {
         old = current;
         old->state=RUNNABLE;
     }
       /* new=&task[1]; */
      new=list_entry(RunableList,struct task_struct,linklist);
      if(new->state==0)
      {
          new=&task[0];
          new->number=0;
      }
      ptr=NULL;
      list_foreach(ptr,RunableList)
       {
      temp=list_entry(ptr,struct task_struct,linklist);
           if((temp->state!=0)&&(new->number<=temp->number))
               new=temp;
           
       }
     init_ticks(); 
     current=new;
  }

加入退出函数,使得进程可以执行完退出,更符合现实情况。当进程运行结束,需要释放PCB,回收进程资源,将其从就绪队列中删除,调用w_quit()完成。
4—13w_quit()函数

void w_quit()
{  
rrent->state=UNUSED;
          nextpid=nextpid-1;
          list_del(&current->linklist);
          current->number=0;
          wait_intr();     
}
  1. 实验验证及分析
    测试程序做了一些修改,来测试程序运行,a程序先延迟五个时钟中断,打印20次退出,b程序打印20次退出,c程序打印16次退出,一个时间片15个时钟中断,当全部退出时系统的当前进程为0号进程,且永不结束,一直等待新的进程创建。
void a(){
       w_delay(5);
    int i=20;
       while(i--){
        printk("A");
        /* printk("%d",current->delay); */
        wait_intr();
    }w_quit(); 
}
void b(){
    int i=20;
    while(i--){
        printk("B");
        /* printk("%d",current->delay); */
        wait_intr();
    }w_quit(); 
}
void c(){
    int i=1;
    for(i=1; i<=16;i++ ){
        printk("C");
        /* printk("%d",current->delay); */
        wait_intr();
    }
    w_quit();
}
void test_proc(){
    creat_kthread(a,"A_proc");
    creat_kthread(b,"B_proc");
    creat_kthread(c,"C_proc");
}

进程调度

《操作系统原理实验指导》 马立肖

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
目录 1 进程的组织 5 1.1 进程相关数据结构 5 1.1.1 进程的基本信息 6 1.1.2 进程状态 10 1.1.3 TASK_RUNNING状态的进程链表 11 1.1.4 进程间关系 12 1.2 Linux的线程——轻量级进程 15 1.3 进程的创建——do_fork()函数详解 19 1.4 执行进程间切换 33 1.4.1 进程切换之前的工作 33 1.4.2 进程切换实务 —— switch_to宏 37 1.4.3 __switch_to函数 39 1.5 fork与vfock系统调用的区别 42 1.6 内核线程 46 1.7 挂起状态进程的组织 49 1.7.1 等待队列头 49 1.7.2 等待队列的操作 50 1.7.3 进程资源限制 55 1.8 系统调用execve() 56 1.8.1 拷贝用户态参数 57 1.8.2 重要的数据结构 61 1.8.3 search_binary_handler函数 66 1.8.4 目标文件的装载和投入运行 69 1.8.5 库函数 92 2 断控制 94 2.1 断的分类 94 2.2 断的硬件环境 95 2.2.1 外部断请求IRQ 95 2.2.2 断描述符表 96 2.2.3 断和异常的硬件处理 97 2.3 断描述符表 99 2.3.1 断门、陷阱门及系统门 99 2.3.2 IDT的初步初始化 100 2.4 异常处理 101 2.5 断处理 106 2.5.1 断向量 107 2.5.2 IRQ数据结构 108 2.5.3 do_IRQ()函数 113 2.5.4 断服务例程 115 2.5.5 IRQ线的动态分配 116 2.6 下半部分 117 2.6.1 软断 118 2.6.2 tasklet 121 2.6.3 工作队列 122 2.7定时器断 124 2.7.1 时钟与定时器 124 2.7.2 定时器断相关的数据结构 127 2.7.3 定时器断的上半部分 129 3 进程调度 138 3.1 进程调度的概念 138 3.2 进程调度的数据结构和优先级 141 3.2.1 进程的优先级 141 3.2.2 数据结构 145 3.3 调度程序所使用的函数 151 3.3.1 scheduler_tick函数 151 3.3.2 try_to_wake_up函数 156 3.3.3 recalc_task_prio函数 160 3.4 schedule()函数 163 3.4.1 直接调用 163 3.4.2 延迟调用 164 3.4.3 进程切换之前所做的工作 168 3.4.4 完成进程切换时所执行的操作 171 3.4.5 进程切换后所执行的操作 173 3.5 多处理器运行队列的平衡 175 3.5.1 调度域 176 3.5.2 rebalance_tick()函数 178 3.5.3 load_balance()函数 180 3.5.4 move_tasks()函数 183 3.6 进程退出 187 3.6.1 进程终止 187 3.6.2 进程删除 189 4 进程的并发性体现 191 4.1 内核抢占 193 4.1.1 内核抢占概念 193 4.1.2 同步技术总揽 196 4.2 每CPU变量 197 4.3 原子操作 199 4.4 优化屏障和内存壁垒 203 4.4.1 优化屏障 204 4.4.2 内存壁垒 204 4.5 自旋锁 206 4.6 读写自旋锁 211 4.6.1 为读获取和释放一个锁 213 4.6.2 为写获取或释放一个锁 214 4.7 顺序锁 215 4.8 RCU机制 217 4.9 信号量 219 4.9.1 获取和释放信号量 221 4.9.2 读/写信号量 224 4.9.3 补充信号量 225 4.10 禁止本地断 226 4.10.1 禁止本地断 227 4.10.2 禁止下半部(可延迟函数) 229 4.11 一些避免竞争条件的实例 231 4.11.1 引用计数器 231 4.11.2 大内核锁 231 4.11.3 内存描述符读/写信号量 232 4.11.4 slab高速缓存链表的信号量 233 4.11.5 索引节点的信号量 233 4.12 内核同步与互斥的总结 233
Linux 内核通过进程管理子系统来管理进程进程管理子系统负责创建、调度和终止进程,并提供了一些系统调用和文件系统接口,使用户空间的程序可以与内核进行交互。 以下是 Linux 内核进行进程管理的一些关键技术: 1. 进程描述符:在 Linux 内核,每个进程都有一个进程描述符(Process Descriptor,简称为 task 或进程控制块 PCB),它包含了进程的所有信息,比如进程状态、进程 ID、进程运行时间、进程优先级等。内核通过进程描述符来管理进程。 2. 进程调度器:进程调度器负责决定哪个进程应该获得 CPU 时间片并执行。Linux 内核有多种进程调度器可供选择,比如 Completely Fair Scheduler(CFS)和 Realtime Scheduler(RT)等。 3. 进程通信:在 Linux 内核进程可以通过多种方式进行通信,比如管道、共享内存、信号量等。这些机制允许进程之间进行数据交换和同步操作。 4. 进程状态:在 Linux 内核进程可以处于不同的状态,比如运行态、就绪态、阻塞态等。内核通过状态转换来管理进程的生命周期。 5. 进程创建和终止:Linux 内核通过 fork() 和 exec() 等系统调用来创建新进程,通过 exit() 系统调用来终止进程。 总之,Linux 内核通过进程管理子系统来管理进程,包括进程描述符、进程调度器、进程通信、进程状态、进程创建和终止等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值