Linux 网络协议栈之内核锁(五)—— 自旋锁在抢占(非抢占)单核和多核中的作用

2024-04-12 01:18

本文主要是介绍Linux 网络协议栈之内核锁(五)—— 自旋锁在抢占(非抢占)单核和多核中的作用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、自旋锁的实现

linux上的自旋锁有三种实现:

1. 在单cpu,不可抢占内核中,自旋锁为空操作。

2. 在单cpu,可抢占内核中,自旋锁实现为“禁止内核抢占”,并不实现“自旋”。

3. 在多cpu,可抢占内核中,自旋锁实现为“禁止内核抢占” + “自旋”。

关于抢占式内核与非抢占式内核:

a、非抢占式内核

如果一个进程在内核态运行,其只有在以下两种情况会被切换:

1.其运行完成(返回用户空间)

2.主动让出cpu(即主动调用schedule或内核中的任务阻塞——这同样也会导致调用schedule)

b、抢占式内核

如果一个进程在内核态运行,其只有在以下四种情况会被切换:

1.其运行完成(返回用户空间)

2.主动让出cpu(即主动调用schedule或内核中的任务阻塞——这同样也会导致调用schedule)

3.当从中断处理程序正在执行,且返回内核空间之前(此时可抢占标志premptcount须为0) 。

4.当内核代码再一次具有可抢占性的时候,如解锁及使能软中断等。

    禁止内核抢占只是关闭“可抢占标志”,而不是禁止进程切换。显式使用schedule或进程阻塞(此也会导致调用schedule)时,还是会发生进程调度的。

二、死锁

1、第一种死锁情况

     死锁发生在多核的情况,下面来分析一下:

     首先,对于多核抢占与多核非抢占的情况,在使用自旋锁时,其情况基本是一致的。因为在多核抢占的情况下,使用自旋锁会禁止内核抢占,这样多核抢占就相当于多核非抢占的情况。

     那下面就只分析多核非抢占的情况。

假设系统有A,B两个CPU。

A上正在运行的a进程已获得自旋锁,并在临界区运行。

B上正在运行的b进程企图获得自旋锁,但由于自旋锁已被占用,于是b进程在B CPU上“自旋”空转。

这时,如果在A上的a进程因程序阻塞,而被休眠。接着A会切换运行另一进程c。

若这个进程c也企图获取自旋锁,c进程同样会因为锁已被占用,而在A上“自旋”空转。

这时候,A上的a进程与c进程就形成了死锁。a进程需要被c进程占用的CPU,c进程需要被a进程占用的锁。

至于在单cpu内核上不会出现上述情况,因为单cpu上的自旋锁实际没有“自旋功能”。

2、第二种死锁情况

     想象你的内核代码请求到一个自旋锁并且在它的临界区里做它的事情,在中间某处,你的代码失去了处理器。或许它已调用了一个函数(copy_from_user,假设)使进程进入眠。也或许,内核抢占发威,一个更高优先级的进程将你的代码推到了一边(注意,这都是假设,自旋锁其实不允许这些操作)。此时,正好某个别的线程想获取同一个锁,如果这个线程运行在和你的内核代码不同的处理器上(幸运的情况),那么它可能要自旋等待一段时间(可能很长),当你的代码从休眠中唤醒或者重新得到处理器并释放锁,它就能得到锁。而最坏的情况是,那个想获取锁得线程刚好和你的代码运行在同一个处理器上,这时它将一直持有CPU进行自旋操作,而你的代码是永远不可能有任何机会来获得CPU释放这个锁了,这就是悲催的死锁。 

3、第三种死锁情况

     spin_lock比spin_lock_irq速度快,但是它并不是任何情况下都是安全的。

举个例子:

     进程A中调用了spin_lock(&lock)然后进入临界区,此时来了一个中断(interrupt),该中断也运行在和进程A相同的CPU上,并且在该中断处理程序中恰巧也会spin_lock(&lock)试图获取同一个锁。由于是在同一个CPU上被中断,进程A会被设置为TASK_INTERRUPT状态,中断处理程序无法获得锁,会不停的忙等,由于进程A被设置为中断状态,schedule()进程调度就无法再调度进程A运行,这样就导致了死锁!

   但是如果该中断处理程序运行在不同的CPU上就不会触发死锁。 因为在不同的CPU上出现中断不会导致进程A的状态被设为TASK_INTERRUPT,只是换出。当中断处理程序忙等被换出后,进程A还是有机会获得CPU,执行并退出临界区。所以在使用spin_lock时要明确知道该锁不会在中断处理程序中使用。

三、自旋锁特性

      自旋锁有几个重要的特性:

1、被自旋锁保护的临界区代码执行时不能进入休眠。

2、被自旋锁保护的临界区代码执行时是不能被被其他中断中断。

3、被自旋锁保护的临界区代码执行时,内核不能被抢占。

从这几个特性可以归纳出一个共性:被自旋锁保护的临界区代码执行时,它不能因为任何原因放弃处理器。 

注:所以现代处理器在处理自旋锁时都会设定自旋上限时间以防死锁. 另自旋锁在单核非抢占式CPU上是无效的.被设为空操作,不做任何事. 

     可能你会奇怪,持有自旋锁的进程在执行内核代码时是不能被抢占的,那么为什么在可抢占式系统中有用呢.其实linux在设计可抢占式系统的自旋锁时只是把自旋锁设计为"只是禁止内核抢占",而没有自旋(所以使用自旋锁的代码一定要可以很快执行完,否则进程就一直持着锁不释放,也不可被抢占).可是理解为只是实现了一个不被打扰的原子操作,操作完后释放锁.所以它不能休眠. 

(211条消息) Linux 网络协议栈之内核锁(五)—— 自旋锁在抢占(非抢占)单核和多核中的作用_zqixiao_09的博客-CSDN博客_自旋锁禁止内核抢占

这篇关于Linux 网络协议栈之内核锁(五)—— 自旋锁在抢占(非抢占)单核和多核中的作用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/895705

相关文章

MySQL日志UndoLog的作用

《MySQL日志UndoLog的作用》UndoLog是InnoDB用于事务回滚和MVCC的重要机制,本文主要介绍了MySQL日志UndoLog的作用,文中介绍的非常详细,对大家的学习或者工作具有一定的... 目录一、Undo Log 的作用二、Undo Log 的分类三、Undo Log 的存储四、Undo

Linux内核定时器使用及说明

《Linux内核定时器使用及说明》文章详细介绍了Linux内核定时器的特性、核心数据结构、时间相关转换函数以及操作API,通过示例展示了如何编写和使用定时器,包括按键消抖的应用... 目录1.linux内核定时器特征2.Linux内核定时器核心数据结构3.Linux内核时间相关转换函数4.Linux内核定时

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

Linux镜像文件制作方式

《Linux镜像文件制作方式》本文介绍了Linux镜像文件制作的过程,包括确定磁盘空间布局、制作空白镜像文件、分区与格式化、复制引导分区和其他分区... 目录1.确定磁盘空间布局2.制作空白镜像文件3.分区与格式化1) 分区2) 格式化4.复制引导分区5.复制其它分区1) 挂载2) 复制bootfs分区3)

Java中自旋锁与CAS机制的深层关系与区别

《Java中自旋锁与CAS机制的深层关系与区别》CAS算法即比较并替换,是一种实现并发编程时常用到的算法,Java并发包中的很多类都使用了CAS算法,:本文主要介绍Java中自旋锁与CAS机制深层... 目录1. 引言2. 比较并交换 (Compare-and-Swap, CAS) 核心原理2.1 CAS

JAVA transient 关键字作用详解

《JAVAtransient关键字作用详解》Java的transient关键字用于修饰成员变量,使其不参与序列化过程,通过自定义序列化方法,可以手动控制transient变量的序列化行为,本文给大... 目录一、transient关键字作用二、原理详解三、典型使用场景四、代码示例五、注意事项六、与 stat

Spring Boot/Spring MVC核心注解的作用详解

《SpringBoot/SpringMVC核心注解的作用详解》本文详细介绍了SpringBoot和SpringMVC中最常用的15个核心注解,涵盖了请求路由映射、参数绑定、RESTfulAPI、... 目录一、Spring/Spring MVC注解的核心作用二、请求映射与RESTful API注解系列2.1

Linux服务器数据盘移除并重新挂载的全过程

《Linux服务器数据盘移除并重新挂载的全过程》:本文主要介绍在Linux服务器上移除并重新挂载数据盘的整个过程,分为三大步:卸载文件系统、分离磁盘和重新挂载,每一步都有详细的步骤和注意事项,确保... 目录引言第一步:卸载文件系统第二步:分离磁盘第三步:重新挂载引言在 linux 服务器上移除并重新挂p

Linux下屏幕亮度的调节方式

《Linux下屏幕亮度的调节方式》文章介绍了Linux下屏幕亮度调节的几种方法,包括图形界面、手动调节(使用ACPI内核模块)和外接显示屏调节,以及自动调节软件(CaliseRedshift和Reds... 目录1 概述2 手动调节http://www.chinasem.cn2.1 手动屏幕调节2.2 外接显

Linux(centos7)虚拟机没有IP问题及解决方案

《Linux(centos7)虚拟机没有IP问题及解决方案》文章介绍了在CentOS7中配置虚拟机网络并使用Xshell连接虚拟机的步骤,首先,检查并配置网卡ens33的ONBOOT属性为yes,然后... 目录输入查看ZFhrxIP命令:ip addr查看,没有虚拟机IP修改ens33配置文件重启网络Xh