同步---自旋锁

1 自旋锁的基本概念

自旋锁最多只能被一个可执行线程持有,如果一个执行线程试图获得一个已经被使用的自旋锁,那么该线程就会一直进行自旋,等待锁重新可用。在任何时刻,自旋锁都可以防止多余一个的执行线程同时进入临界区。

Linux内核实现的自旋锁是不可递归的,如果你请求一个你已经持有的自旋锁,那么你将会自旋,等待释放这个锁,由于自旋,释放这个锁的操作不会被执行,所以会一直处于自旋忙等待中,于是就被锁死了。

自旋锁可以在中断处理程序中使用。在中断处理程序中使用自旋锁时,一定要在获取锁之前,首先禁止本地中断(当前处理器上的中断请求),否则,中断处理程序就会打断正持有锁的内核代码,有可能试图去争用这个已经被持有的自旋锁,这样一来,中断处理程序就会自旋,但是锁的持有者在这个中断处理程序执行完毕前不可能运行,会造成死锁。注意,需要关闭的只是当前处理器上的中断,如果中断发生在不同的处理器上,即使中断处理程序在同一锁上自旋,也不会妨碍锁的持有者最终释放锁。

自旋锁的实现和体系结构体密切相关,代码往往通过汇编实现,这些与体系结构相关的代码定义在文件asm/spinlock.h中,实际需要用到的接口定义在文件linux/spinlock.h中,内核提供了对自旋锁的操作接口:
请添加图片描述

2 自旋锁在内核的实现

spinlock_t

自旋锁用spinlock_t的实例表示,spinlock_t定义在include/linux/spinlock_types.h

typedef struct spinlock {union {struct raw_spinlock rlock;#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))struct {u8 __padding[LOCK_PADSIZE];struct lockdep_map dep_map;};
#endif};
} spinlock_t;

spinlock_t由raw_spinlock表示,该类型和spinlock_t定义在同一个文件中:

typedef struct raw_spinlock {arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAKunsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCKunsigned int magic, owner_cpu;void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;
#endif
} raw_spinlock_t;

raw_spinlock由arch_spinlock_t 表示,arch_spinlock_t的实现与体系结构相关,所以spinlock_t的实现与体系结构相关,我们看arm实现的代码,在文件arch/arm/include/asm/spinlock_types.h中:

typedef struct {union {u32 slock;struct __raw_tickets {
#ifdef __ARMEB__u16 next;u16 owner;
#elseu16 owner;u16 next;
#endif} tickets;};
} arch_spinlock_t;

owner表示持有这个数字的thread可以获得自旋锁,next表示如果后续再有thread请求获取这个自旋锁,就给他分配这个数字。

spinlock的实现原理:

  1. 刚开始owner=next=0
  2. 第一个thread获取spinlock,可获取成功,此时owner=0,next=0
  3. 第二个thread获取spinlock,如果第一个thread还没有释放spinlock,则next++,next变为1
  4. 第三个thread获取spinlock,如果第一个thread还没有释放spinlock,则next++,next就变为2
  5. 此时第一个thread释放spinlock,则执行owner++,owner=1
  6. 虽然此时第二个thread和第三个thread都在等待spinlock,但是因为第二个thread的next=owner,所以第二个thread可以获取spinlock,第三个spinlock继续等待

这样保证了spinlock的唤醒机制是先到先唤醒,后到后唤醒,保证了公平性。

spin_lock_init

spin_lock_init的定义在include/linux/spinlock.h中

#define spin_lock_init(_lock)				\
do {							\spinlock_check(_lock);				\raw_spin_lock_init(&(_lock)->rlock);		\
} while (0)

spin_lock_init只是对_lock做了一些检查,我们看raw_spin_lock_init的具体实现,只对spinlock_t中的rlock的初始化。raw_spin_lock_init的实现如下,lock是struct raw_spinlock类型

# define raw_spin_lock_init(lock)				\do { *(lock) = __RAW_SPIN_LOCK_UNLOCKED(lock); } while (0)
#endif
#define __RAW_SPIN_LOCK_UNLOCKED(lockname)	\(raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname)#define __RAW_SPIN_LOCK_INITIALIZER(lockname)	\{					\.raw_lock = __ARCH_SPIN_LOCK_UNLOCKED,	\SPIN_DEBUG_INIT(lockname)		\SPIN_DEP_MAP_INIT(lockname) }

__ARCH_SPIN_LOCK_UNLOCKED的值与体系架构有关,在arm架构上:

#define __ARCH_SPIN_LOCK_UNLOCKED	{ { 0 } }

SPIN_DEBUG_INIT(lockname)、SPIN_DEP_MAP_INIT(lockname)是为了调试的,如果不调试什么都不做,所以spin_lock_init只是将互斥锁设置为没有被锁住的状态,即raw_lock的值设为__ARCH_SPIN_LOCK_UNLOCKED

spin_lock

spin_lock的实现在include/linux/spinlock.h中

static __always_inline void spin_lock(spinlock_t *lock)
{raw_spin_lock(&lock->rlock);
}#define raw_spin_lock(lock)	_raw_spin_lock(lock)

spin_lock在单核(up)和多核(smp)的实现不同。

up

在一个处理器下,在文件include/linux/spinlock_api_up.h中定义

#define _raw_spin_lock(lock)			__LOCK(lock)
#define __LOCK(lock) \do { preempt_disable(); ___LOCK(lock); } while (0)

只是关闭了抢占功能

smp

在多处理器下,在文件include/linux/spinlock_api_smp.h中定义

#define _raw_spin_lock(lock) __raw_spin_lock(lock)static inline void __raw_spin_lock(raw_spinlock_t *lock)
{preempt_disable();spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}

__raw_spin_lock的实现靠do_raw_spin_lock

void do_raw_spin_lock(raw_spinlock_t *lock)
{debug_spin_lock_before(lock);arch_spin_lock(&lock->raw_lock);debug_spin_lock_after(lock);
}

可以看到do_raw_spin_lock的实现与体系结构有关,因为调用了arch_spin_lock,arch_spin_lock中会将next值加1,然后一直判断next和onwer是否相同,如果相同,则获取锁,进入临界区执行,否则会一直判断

所以spin_lock首先会禁止抢占,接着看能不能获得锁,如果能够获得锁,则进入临界区,不能获得,则一直判断,直到可以进去临界区。

spin_unlock

spin_unlock定义在include/linux/spinlock.h中

static __always_inline void spin_unlock(spinlock_t *lock)
{raw_spin_unlock(&lock->rlock);
}
#define raw_spin_unlock(lock)		_raw_spin_unlock(lock)

_raw_spin_unlock在多处理器(SMP)和单处理器(UP)的实现不同

up

在include/linux/spinlock_api_up.h中

#define _raw_spin_unlock(lock)			__UNLOCK(lock)#define __UNLOCK(lock) \do { preempt_enable(); ___UNLOCK(lock); } while (0)

仅仅允许抢占

smp

#define _raw_spin_unlock(lock) __raw_spin_unlock(lock)
static inline void __raw_spin_unlock(raw_spinlock_t *lock)
{spin_release(&lock->dep_map, 1, _RET_IP_);do_raw_spin_unlock(lock);preempt_enable();
}

spin_unlock在单处理器下,把抢占设为允许,在多处理器下,先将owner增加1,然后把抢占设为允许

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/379561.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实习日志----4.播放时段参数设置

由于客户在下发广告时,一则广告可在多个时段播放,这就需要设置多个播放时段的参数。 但在这种情况下,我并不知道用户每次需要下发几个时段,所以前台不能设定死。 因此我要实现这么一个功能,让用户根据自己的需要来动态…

线性插值算法实现图像_C程序实现插值搜索算法

线性插值算法实现图像Problem: 问题: We are given an array arr[] with n elements and an element x to be searched amongst the elements of the array. 给定一个数组arr [],其中包含n个元素和一个要在该数组的元素中搜索的元素x 。 Solution: 解&…

hdu 1197

地址&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1197 题意&#xff1a;求一个数转换成10&#xff0c;12&#xff0c;16进制后各个位上的数的和是否相等。 mark&#xff1a;模拟进制转换。 代码&#xff1a; #include <stdio.h>int zh(int a, int n) {int su…

linux系统编程---线程总结

线程总结1 线程的实现线程创建线程退出线程等待线程清理2 线程的属性线程的分离线程的栈地址线程栈大小线程的调度策略线程优先级3 线程的同步互斥锁读写锁条件变量信号量线程是系统独立调度和分配的基本单位。同一进程中的多个线程将共享该进程中的全部系统资源&#xff0c;例…

博客上一些项目相关源码链接

GitHub&#xff1a;https://github.com/beyondyanyu/Sayingyy

重新开启Ctrl+Alt+Backspace快捷键

UBUNTU老用户知道CtrlAltBackspace这个快捷键是用来快速重启X的在9.04中被默认关闭了&#xff0c;那如何来打开它呢&#xff1f;在终端中输入&#xff1a;sudo gedit /etc/X11/xorg.conf在其中加入&#xff1a;Section “ServerFlags”Option “DontZap” “false”EndSection退…

Java LocalDate类| 带示例的getDayOfYear()方法

LocalDate类的getDayOfYear()方法 (LocalDate Class getDayOfYear() method) getDayOfYear() method is available in java.time package. getDayOfYear()方法在java.time包中可用。 getDayOfYear() method is used to get the day-of-year field value of this LocalDate obje…

火腿三明治定理

定理&#xff1a;任意给定一个火腿三明治&#xff0c;总有一刀能把它切开&#xff0c;使得火腿、奶酪和面包片恰好都被分成两等份。 而且更有趣的是&#xff0c;这个定理的名字真的就叫做“火腿三明治定理”&#xff08;ham sandwich theorem&#xff09;。它是由数学家亚瑟•斯…

如何给Linux操作系统(CentOS 7为例)云服务器配置环境等一系列东西

1.首先&#xff0c;你得去购买一个云服务器&#xff08;这里以阿里云学生服务器为例&#xff0c;学生必须实名认证&#xff09; 打开阿里云&#xff0c;搜索学生服务器点击进入即可 公网ip为连接云服务器的主机 自定义密码为连接云服务器是需要输入的密码 购买即可 点击云服…

Linux系统编程---I/O多路复用

文章目录1 什么是IO多路复用2 解决什么问题说在前面I/O模型阻塞I/O非阻塞I/OIO多路复用信号驱动IO异步IO3 目前有哪些IO多路复用的方案解决方案总览常见软件的IO多路复用方案4 具体怎么用selectpollepolllevel-triggered and edge-triggered状态变化通知(edge-triggered)模式下…

[转帖]纯属娱乐——变形金刚vs天网

[转帖]变形金刚2的影评-《变形金刚3 天网反击战》有一个问题困扰了我足足二十年&#xff1a;为什么汽车人要帮地球人&#xff1f;光用“所有有感知的生物都应享有自由”这个法则是根本说不过去的&#xff0c;因为猪也有感知&#xff0c;但人类就把猪圈养起来&#xff0c;随意杀…

c#中textbox属性_C#.Net中的TextBox.MaxLength属性与示例

c#中textbox属性Here we are demonstrating use of MaxLength property of TextBox. 在这里&#xff0c;我们演示了TextBox的MaxLength属性的使用。 MaxLength property of TextBox is used to set maximum number of character that we can input into a TextBox. Limit of M…

IIS7 MVC网站生成、发布

(1)生成。 确保System.Web.Mvc.dll在bin目录下 (2)发布网站到文件系统 (3)在IIS中为网站添加应用程序池&#xff08;一个虚拟目录&#xff0c;一个应用程序池&#xff09; (4)添加在默认网站下添加虚拟目录 &#xff08;5&#xff09;转换为应用程序 至此&#xff0c;部署完毕 …

标题:明码

转载&#xff1a;https://blog.csdn.net/u011747888/article/details/79781040 标题&#xff1a;明码 汉字的字形存在于字库中&#xff0c;即便在今天&#xff0c;16点阵的字库也仍然使用广泛。 16点阵的字库把每个汉字看成是16x16个像素信息。并把这些信息记录在字节中。 一…

C语言多维数组

文章目录多维数组数组名下标指向数组的指针作为函数参数的多维数组指针数组小结多维数组 如果某个数组的维数超过1&#xff0c;它就被称为多维数组&#xff0c;例如&#xff0c;下面这个声明&#xff1a; int matrix[6][10]创建了一个包含60个元素的矩阵。但是&#xff0c;它…

ubuntu路由器联网_路由器及其协议简介| 联网

ubuntu路由器联网路由器简介 (Introduction to Router) Routers are network layer devices. Data on the network layer is known as packets. Routers work to forward packets from one network to another. Routers also maintain the address table. 路由器是网络层设备。…

XPath学习:轴(5)——descendant-or-self

XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。 XPath 是 W3C XSLT 标准的主要元素&#xff0c;并且 XQuery 和 XPointer 同时被构建于 XPath 表达之上。 推荐一个挺不错的网站&#xff1a;http://www.zvon.org/xxl/XPathTutorial…

linux设备驱动开发---平台设备驱动程序

文章目录1 平台驱动程序2 平台设备2.1 资源和平台数据1 设备配置---废弃的旧方法资源平台数据声明平台设备2 设备配置---推荐的新方法3 设备、驱动程序和总线匹配OF风格ACPIID表匹配匹配平台设备的名字和平台驱动的名字平台设备和平台驱动程序如何匹配4 Platfrom架构驱动程序有…

标题:乘积尾零

标题&#xff1a;乘积尾零 如下的10行数据&#xff0c;每行有10个整数&#xff0c;请你求出它们的乘积的末尾有多少个零&#xff1f; 5650 4542 3554 473 946 4114 3871 9073 90 4329 2758 7949 6113 5659 5245 7432 3051 4434 6704 3594 9937 1173 6866 3397 4759 7557 3070…

Robots.txt指南

Robots.txt指南当搜索引擎访问一个网站时&#xff0c;它首先会检查该网站的根域下是否有一个叫做robots.txt的纯文本文件。Robots.txt文件用于限定搜索引擎对其 网站的访问范围&#xff0c;即告诉搜索引擎网站中哪些文件是允许它进行检索(下载)的。这就是大家在网络上常看到的“…