首页 > 系统相关 >2、进程、线程、中断的核心:栈

2、进程、线程、中断的核心:栈

时间:2024-07-21 16:30:52浏览次数:10  
标签:中断 线程 key 按键 进程 CPU

1 进程、线程、中断的核心:栈

中断中断,中断谁?

中断当前正在运行的进程、线程。

进程、线程是什么?内核如何切换进程、线程、中断?

要理解这些概念,必须理解栈的作用。

1.1 ARM处理器程序运行的过程

ARM芯片属于精简指令集计算机(RISC:Reduced Instruction Set Computing),它所用的指令比较简单,有如下特点:

① 对内存只有读、写指令

② 对于数据的运算是在CPU内部实现

③ 使用RISC指令的CPU复杂度小一点,易于设计

比如对于a=a+b这样的算式,需要经过下面4个步骤才可以实现:

 

 

 

细看这几个步骤,有些疑问:

① 读a,那么a的值读出来后保存在CPU里面哪里?

② 读b,那么b的值读出来后保存在CPU里面哪里?

③ a+b的结果又保存在哪里?

 

我们需要深入ARM处理器的内部。简单概括如下,我们先忽略各种CPU模式(系统模式、用户模式等等)。

注意:如果想入理解ARM处理器架构,应该从裸机开始学习。我们即将写好近30个裸机程序的文档,估计还3月底发布。

注意:为了加快学习速度,建议先不看裸机。

 

CPU运行时,先去取得指令,再执行指令:

① 把内存a的值读入CPU寄存器R0

② 把内存b的值读入CPU寄存器R1

③ 把R0、R1累加,存入R0

④ 把R0的值写入内存a

1.2程序被中断时,怎么保存现场

从上图可知,CPU内部的寄存器很重要,如果要暂停一个程序,中断一个程序,就需要把这些寄存器的值保存下来:这就称为保存现场。

保存在哪里?内存,这块内存就称之为栈。

程序要继续执行,就先从栈中恢复那些CPU内部寄存器的值。

这个场景并不局限于中断,下图可以概括程序A、B的切换过程,其他情况是类似的:

 

 

 

 

 

a. 函数调用:

在函数A里调用函数B,实际就是中断函数A的执行。

那么需要把函数A调用B之前瞬间的CPU寄存器的值,保存到栈里;

再去执行函数B;

函数B返回之后,就从栈中恢复函数A对应的CPU寄存器值,继续执行。

b. 中断处理

进程A正在执行,这时候发生了中断。

CPU强制跳到中断异常向量地址去执行,

这时就需要保存进程A被中断瞬间的CPU寄存器值,

可以保存在进程A的内核态栈,也可以保存在进程A的内核结构体中。

中断处理完毕,要继续运行进程A之前,恢复这些值。

c. 进程切换

在所谓的多任务操作系统中,我们以为多个程序是同时运行的。

如果我们能感知微秒、纳秒级的事件,可以发现操作系统时让这些程序依次执行一小段时间,进程A的时间用完了,就切换到进程B。

怎么切换?

切换过程是发生在内核态里的,跟中断的处理类似。

进程A的被切换瞬间的CPU寄存器值保存在某个地方;

恢复进程B之前保存的CPU寄存器值,这样就可以运行进程B了。

 

所以,在中断处理的过程中,伴存着进程的保存现场、恢复现场。

进程的调度也是使用栈来保存、恢复现场:

 

 

1.3进程、线程的概念

假设我们写一个音乐播放器,在播放音乐的同时会根据按键选择下一首歌。把事情简化为2件事:发送音频数据、读取按键。那可以这样写程序:

int main(int argc, char **argv)

{

  int key;

  while (1)

  {

    key = read_key();

    if (key != -1)

    {

      switch (key)

      {

        case NEXT:

            select_next_music(); // 在GUI选中下一首歌

            break;

       }

      }

     else

     {

      send_music();

     }

    }

    return 0;

}

这个程序只有一条主线,读按键、播放音乐都是顺序执行。

无论按键是否被按下,read_key函数必须马上返回,否则会使得后续的send_music受到阻滞导致音乐播放不流畅。

读取按键、播放音乐能否分为两个程序进行?可以,但是开销太大:读按键的程序,要把按键通知播放音乐的程序,进程间通信的效率没那么高。

这时可以用多线程之编程,读取按键是一个线程,播放音乐是另一个线程,它们之间可以通过全局变量传递数据,示意代码如下:

int g_key;

void key_thread_fn()

{

  while (1)

  {

    g_key = read_key();

    if (g_key != -1)

    {

      switch (g_key)

      {

        case NEXT:

          select_next_music(); // 在GUI选中下一首歌

          break;

      }

    }

  }

}

void music_fn()

{

  while (1)

  {

    if (g_key == STOP)

      stop_music();

    else

    {

           send_music();

    }

  }

}

 

int main(int argc, char **argv)

{

  int key;

  create_thread(key_thread_fn);

  create_thread(music_fn);

  while (1)

  {

    sleep(10);

  }

  return 0;

}

这样,按键的读取及GUI显示、音乐的播放,可以分开来,不必混杂在一起。

按键线程可以使用阻塞方式读取按键,无按键时是休眠的,这可以节省CPU资源。

音乐线程专注于音乐的播放和控制,不用理会按键的具体读取工作。

并且这2个线程通过全局变量g_key传递数据,高效而简单。

 

在Linux中:资源分配的单位是进程,调度的单位是线程。

也就是说,在一个进程里,可能有多个线程,这些线程共用打开的文件句柄、全局变量等等。

而这些线程,之间是互相独立的,“同时运行”,也就是说:每一个线程,都有自己的栈。如下图示:

 

 

 

 

调度的单位是线程,‌这是因为线程是操作系统中进行运算调度和执行的基本单位。‌线程被包含在进程之中,‌是进程中的实际运作单位,‌一条线程指的是进程中一个单一顺序的控制流。‌一个进程中可以并发多个线程,‌每条线程并行执行不同的任务。‌线程可以是内核线程,‌由操作系统内核调度,‌也可以是用户线程,‌由用户进程自行调度,‌或者是内核与用户进程混合调度。‌

 

线程与进程的区别和联系在于:‌

 

  • 进程是资源分配的基本单位,‌每个进程都有独立的内存空间(‌虚拟地址空间)‌,‌而线程则共享所属进程的虚拟地址空间。‌
  • 线程不能独立于进程而存在,‌一个进程里可以有一个线程,‌也可以有多个线程。‌
  • 线程的引入显著提高了系统的并发程度,‌使得在同一进程中多个线程的切换不会引起进程切换,‌从而提高了系统资源的使用效率和吞吐量。‌
  • 线程基本上不拥有资源,‌但它可以访问其所属进程的全部资源,‌如代码段、‌数据段及系统资源。‌
  • 创建或撤销线程的开销远小于创建或撤销进程的开销,‌因为线程切换不需要涉及存储管理的操作,‌而进程切换则需要保存和恢复执行环境,‌开销较大。‌

 

因此,‌将调度的单位定为线程,‌可以更有效地利用系统资源,‌提高系统的并发性和效率

 

标签:中断,线程,key,按键,进程,CPU
From: https://www.cnblogs.com/liusiluandzhangkun/p/18314615

相关文章

  • Java 多线程
    文章目录一、概念二、实现方式2.1Thread类2.2Runnable接口三、常用方法3.1基本方法3.2线程优先级3.3守护线程3.4礼让线程3.5插队线程四、线程安全问题4.1同步代码块4.2同步方法4.3lock()五、线程生命周期一、概念在Java中,多线程是指在一个程序中同......
  • ARM体系结构和接口技术(十)按键中断实验①
    一、按键中断实验(一)分析按键电路图(二)芯片手册二、按键中断实验分析注:NVIC----Cortx-M核GIC----Cortx-A核(一)查看所有外设的总线以及寄存器基地址注:GIC的总线是A7核的内部总线,也就是说,它是由ARM公司完成的注:EXTI的时钟源无需手动使能,它一直是使能状态(二)RCC章节(......
  • 0、软中断与硬中断的区别
    一、硬中断由与系统相连的外设(比如网卡、硬盘)自动产生的,主要是用来通知操作系统系统外设状态的变化。可屏蔽中断——当CPU接收到更高优先级的中断时,这些中断可以被延迟。不可屏蔽中断——无法延迟这些中断。CPU应该立即考虑它们。二、软中断为了满足实时系统的要求,中断......
  • 蓝桥杯单片机学习(Day14 实现操作外部开启中断)
    外部中断相关寄存器的配置方法和触发方式:        实验配置:    [email protected],J3跳线配置为IO方式,J5配置为BTN、J2配置为1-3和2-4。配置方法:        EX0、IT0负责外部中断0服务函数的开启其中断服务函数优先级为interrupt0,EX1、IT1负责......
  • 1、异常与中断的概念及处理流程
     1中断的引入1.1妈妈怎么知道孩子醒了妈妈怎么知道卧室里小孩醒了?①时不时进房间看一下:查询方式简单,但是累②进去房间陪小孩一起睡觉,小孩醒了会吵醒她:休眠-唤醒不累,但是妈妈干不了活了③妈妈要干很多活,但是可以陪小孩睡一会,定个闹钟:poll方式要浪费点时间,但是可以继......
  • 一文揭开JDK21虚拟线程的神秘面纱
    虚拟线程快速体验环境:JDK21+IDEApublicstaticvoidmain(String[]args){try(varexecutor=Executors.newVirtualThreadPerTaskExecutor()){IntStream.range(0,10_000).forEach(i->{executor.submit(()->{Thread.sle......
  • 一文揭开JDK21虚拟线程的神秘面纱
    虚拟线程快速体验环境:JDK21+IDEApublicstaticvoidmain(String[]args){try(varexecutor=Executors.newVirtualThreadPerTaskExecutor()){IntStream.range(0,10_000).forEach(i->{executor.submit(()->{Threa......
  • java多线程等待唤醒机制详细介绍
    java多线程等待唤醒机制一.方法介绍方法说明voidwait()线程等待,等待的过程中线程会释放锁,需要被其他线程调用notify方法将其唤醒,重新抢锁执行voidnotify()线程唤醒,一次唤醒一个等待线程;如果有多条线程等待,则随机唤醒一条等待线程voidnotifyAll()唤醒所有等待线......
  • 多线程同步利器:条件变量 Condition Variable 的深度解析
    ......
  • 多线程同步机制中 lock_guard 与 unique_lock 的使用区别
    ......