SpinLock自旋锁

C++实现自旋锁SpinLock 自旋锁是一种机制,用于多线程编程中保护共享资源。与普通的阻塞不同,自旋锁在获取不到时,线程不会被挂起,而是持续循环(“自旋”)检查是否可用。当被释放时,线程立即获取进入临界区。自旋锁适用于短时间的临界区操作,因为它避免了线程上下文切换的开销,但在长时间等待时会浪费大量 CPU 资源。自旋锁是一种用于多线程环境下的同步机制,能够确保在同一时间只有一个线程能够访问共享资源。 阅读详情

目录

当线程执行发生资源冲突时,一般有两种锁的解决方案,一种是挂起当前线程、调起其他线程,未获取到锁的线程将进入阻塞,另外一种是等待当前线程执行完毕。后面这一种就是本文将要讲到的自旋锁SpinLock。

SpinLock自旋锁定义

自旋锁是指在多线程环境中共享资源冲突情况下,线程反复执行检查锁变量是否可用的一种锁机制。

SpinLock简单示例

自旋锁


import java.util.concurrent.atomic.AtomicReference;

public class SpinLock {
	public AtomicReference<Thread> ar = new AtomicReference();
	
	public void lock(){
		Thread th = Thread.currentThread();
		while(!ar.compareAndSet(null, th)){
			System.out.println(th.getName()+" is Spinning!");
		}
		
	}
	
	public void unlock(){
		Thread th = Thread.currentThread();
		if(ar.get()!=th){
			System.out.println("Exception");
		}
		ar.set(null);
	}
	
}

public class TestSpinLock {
	static int count=0;
	public static void main(String args[]) throws InterruptedException{
		ExecutorService executors = Executors.newFixedThreadPool(100);
		CountDownLatch countdown = new CountDownLatch(100);
		SpinLock spinlock = new  SpinLock();
		for(int i =0;i<100;i++){
			executors.execute(new Runnable(){

				@Override
				public void run() {
					// TODO Auto-generated method stub
					spinlock.lock();
					count++;
					spinlock.unlock();
					countdown.countDown();
				}
				
			});
		}
		countdown.await();
		System.out.print(count);
	}
}
测试结果:
pool-1-thread-4 is Spinning!
pool-1-thread-5 is Spinning!
pool-1-thread-3 is Spinning!
pool-1-thread-1 is Spinning!
100

运行多次结果,其中输出自旋的线程号存在不同,但最后结果均为100,锁的功能基本实现。

SpinLock中CAS经典ABA问题

SpinLock实现过程中会用到CAS(Compare And Swap)方式,CAS有三个操作值,内存值M,预期值A,修改操作值B,如果M等于A,则将内存值修改为B。如果两次CAS正好是A->B->A,则CAS会认为未发生变化。针对这类问题,可以引入版本号,如1A->2B->3A。如果涉及到多个变量的原子操作可以考虑拼接多变量成一个字符串的方式。JDK1.5以后提供了类似版本号的这种方式AtomicStampedReference,如下所描述的这样,“An AtomicStampedReference maintains an object reference along with an integer “stamp”, that can be updated atomically”.

SpinLock死锁问题探讨

以本文的简单示例继续探讨SpinLock可能死锁的问题,先看以下代码:


public class TestSpinLockWithDeadLock implements Runnable{
	
	public SpinLock lock;
	public TestSpinLockWithDeadLock(SpinLock lock){
		this.lock=lock;
	}
	
	
	public static void main(String args[]){
		SpinLock spinlock = new SpinLock();
		TestSpinLockWithDeadLock th= new TestSpinLockWithDeadLock(spinlock);
		Thread t = new Thread(th);
		t.start();
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		this.lock.lock();;
		this.lock.lock();
		System.out.println("Running");
		this.lock.unlock();
		this.lock.unlock();
	}
	
}

Console控制台中循环打印以下输出,无法停止下来。

Thread-0 is Spinning!
Thread-0 is Spinning!
Thread-0 is Spinning!
Thread-0 is Spinning!
Thread-0 is Spinning!

可见如果同一线程重复加锁会导致死锁问题,即不可重入,如果需要重入,需要在SpinLock中加入计数器进行if-else判断,是同一进程则进行自增自减处理,否则进行CAS操作。在Linux内核中如果同一CPU上某线程持有锁A,中断后中断上下文继续尝试获得该锁,则也会导致死锁。

Ubuntu22.04下ROS2与PX4仿真环境搭建全流程解析 本文详细解析了在Ubuntu22.04系统下搭建ROS2与PX4仿真环境的全流程,包括系统准备、ROS2 Humble安装、PX4飞控环境部署、ROS2与PX4通信桥梁搭建等关键步骤。针对常见问题提供了解决方案,并分享了性能优化和开发调试技巧,帮助开发者快速构建无人机仿真开发环境。 阅读详情

相关推荐

深入理解SQL注入中的union select 1,2,3....

UNION 用于合并两个查询的结果集

渗透之路,攻防之间皆学问 2万+

【Linux内核】自旋锁spinlock机制

define __lockfunc __section(".spinlock.text") __lockfunc 是一个宏,用于将下面的函数定义放置到 . spinlock . text 段中。. spinlock . text 是Linux内核中专门用于存放自旋锁相关代码的代码段。由于自旋锁是用于保护共享资源的关键机制,因此其实现需要非常高效和可靠。将自旋锁相关代码放置在独立的代码段中,可以使得该部分代码具有更好的可读性、可维护性和可移植性,并且不会被其他部分的代码所干扰。

逆风水手的博客 2469

spinlock:自旋锁的不同实现

来自Lockless Inc 的这篇文章的各种自旋锁实现。 我做了一些修改以使每个实现自包含并提供一个基准脚本。 代码依赖 GCC 的内置函数进行原子内存访问。 注意:可伸缩性是通过避免共享和争用来实现的,而不是通过可伸缩来实现的。

详解自旋锁

自旋锁Spinlock)是一种用于保护临界区的同步机制,其主要特点是通过循环检测的状态来避免线程或进程的阻塞。在自旋锁的实现中,当一个线程尝试获取已被其他线程占用的时,它不会进入睡眠状态,而是持续循环检查的状态,直到被释放为止。自旋锁在Linux内核中得到了广泛应用,特别是在中断处理和设备驱动程序中。Linux内核提供了多种自旋锁API,如spin_lock、spin_lock_irqsave等,用于不同场景下的操作。

如无必要,勿增实体。 1684

spinlock(自旋锁)zz

1,自旋锁 自旋锁与互斥有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了,"自旋"一词就是因此而得名。   由于自旋锁使用者一般保持时间非常短,因此选择自旋而不是睡眠是非常必要的,自旋锁的效率远高于互斥。   信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只...

anjuenz87013的博客 143

Linux spinlock自旋锁原理深度剖析(基于ARM32/64 )

自旋锁的概念 自旋锁(spin lock)是一种典型的对临界资源进行互斥访问的手段,自旋锁最多只能被一个可执行线程持有,如果一个执行线程试图获得一个被已经持有(争用)的自旋锁,那么该线程就会一直进行忙循环-旋转-等待重新可用,要是未被争用,请求的执行线程就可以立即得到它,继续执行。 自旋锁相关操作 定义自旋锁 spinlock_t lock; 初始化自旋锁 spin_lock_init(lock); 获得自旋锁 spin_lock(lock); 该宏用于获得自旋锁lock,如果能够立即获得,它就马

longyuelang的专栏 3293

什么是自旋锁SpinLock

当一个线程尝试获取自旋锁时,如果发现已经被其他线程持有,它会在循环中不断地检查的状态,而不是被挂起或阻塞。与传统的阻塞不同,自旋锁在获取时不会主动阻塞线程,而是通过循环不断地尝试获取,如果获取的操作可能会引起线程的阻塞,使用自旋锁就不合适,应该选择其他类型的。需要注意的是,自旋等待的过程会占用CPU资源,因此在实际应用中,需要根据具体的场景和需求来选择合适的机制。加的时候,如果是空的,则将线程丢进去,将其无限循环,就是自旋锁。解的时候,如果是期望的线程,我们就将其设为空。

Li2992673708的博客 5003

Linux中自旋锁spinlock的实现

本文分析了Linux内核自旋锁(spinlock)的实现机制。主要内容包括: 自旋锁的核心特性:采用忙等待机制,当被占用时请求线程会循环检查状态而非睡眠。 关键实现技术: 使用独立的代码段(.text.lock.*)存放相关代码,优化指令缓存 通过xchgb指令实现原子性状态交换 结合preempt_disable/enable保证加过程的原子性 主要函数实现: spin_trylock:非阻塞尝试加 _raw_spin_trylock:底层原子交换实现 spin_lock:完整加流程 多处理

weixin_51019352的博客 782

Linux 内核自旋锁spinlock(四)--- queued spinlock

Linux 内核自旋锁spinlock(四)--- queued spinlock简介。

小立仔 2062

ARM下的自旋锁spinlock

本文讲述的是linux 4.7.1下ARM architecture的自旋锁spinlock的实现。 先来看定义: include/linux/spinlock_types.h 我们不考虑CONFIG_DEBUG_LOCK_ALLOC, spinlock_t结构体中只有一个成员struct raw_spinlock rlock. struct raw_spinlock也只有一个成员arch_spinlock_t raw_lock. arch/arm/include/asm/spinlock_ty

shaohui973的专栏 1521

自旋锁spinlock

1 在单处理器上的实现 单核系统上,不存在严格的并发,因此对资源的共享主要是多个任务分时运行造成的。 只要在某一时段,停止任务切换,并且关中断(对于用户态应用程序,不大可能与中断处理程序抢临界区资源),或者对临界区资源的访问可以用一条原子指令完成,就能够保证只有一个任务在运行。 这就是spinlock的实现机制。 1: #define __LOCK(lock) \ 2: do { ...

weixin_34293902的博客 785

SpinLock(自旋锁)

SpinLock结构是一个低级别的互斥同步基元,它在等待获取时进行旋转。 在多核计算机上,当等待时间预计较短且极少出现争用情况时,SpinLock 的性能将高于其他类型的。 不过,仅在通过分析确定 System.Threading.Monitor 方法或 Interlocked 方法显著降低了程序的性能时使用 SpinLock。......

xiaokaiv587的博客 489

并发编程 - 线程同步(八)之自旋锁SpinLock

首先互斥Monitor在获取时会阻塞线程,同时线程会进行上下文切换,把CPU资源让出来给其他线程使用,直到可用。SpinLock是C#中轻量级,通过自旋避免线程上下文切换。SpinLock是一个结构体,使用上和Monitor类很像,都是通过Enter或TryEnter方法持有,同时默认支持lockTaken模式,然后通过Exit释放。在传递SpinLock实例时,需要十分小心,这是因为SpinLock是结构体即为值类型,当通过值传递,会导致创建该结构体的副本,复制一个新的实例,而不是传递引用。

weixin_55010563的博客 746

自旋锁,信号量,互斥量的实现

数据结构:根据前面的分析,我们可以基本推断出spin lock的实现。首先定义一个spinlock_t的数据类型,其本质上是一个整数型(对该数值的操作需要保证原子性),该数值表示spin lock是否可用。初始化的时候被设定为1.当thread想要持有的时候调用spin_lock函数,该函数将spin lock按个证书值减去1,然后进行判断如果等于0,表示可以获取spinlock,如果时负数,则说明其他thread的持有该,本thread需要spin。

2301_76226118的博客 1615

Linux内核自旋锁详解

自旋锁(Spinlock)是Linux内核中最基本的同步机制之一,特别适用于嵌入式系统中的短期定需求。它通过"忙等"方式实现,持续检查是否可用,而不会让出处理器。自旋锁是嵌入式Linux系统中重要的同步机制,适合短临界区保护。在资源受限的嵌入式环境中,正确使用自旋锁能有效避免竞态条件,同时保持系统的响应性和效率。但需要谨慎设计定策略,避免性能问题和死风险。

weixin_63577471的博客 1151

互斥自旋锁、悲观、乐观的应用场景

互斥自旋锁:谁更轻松自如? 最底层的两种就是会「互斥自旋锁」,有很多高级的都是基于它们实现的,你可以认为它们是各种的地基,所以我们必须清楚它俩之间的区别和应用。 加的目的就是保证共享资源在任意时间里,只有一个线程访问,这样就可以避免多线程导致共享数据错乱的问题。 当已经有一个线程加后,其他线程加则就会失败,互斥自旋锁对于加失败后的处理方式是不一样的: 互斥失败后,线程会释放 CPU,给其他线程; 自旋锁失败后,线程会忙等待,直到它拿到; 互斥是一种「独.

weixin_43606861的博客 394

认真的讲一讲:自旋锁到底是什么

什么是自旋锁自旋锁spinlock):是指当一个线程在获取的时候,如果已经被其它线程获取,那么该线程将循环等待,然后不断的判断是否能够被成功获取,直到获取到才会退出循环。 获取的线程一直处于活跃状态,但是并没有执行任何有效的任务,使用这种会造成busy-waiting。 Java如何实现自旋锁? 下面是个简单的例子: /** * Date: 2016年1月4日 下午4:41:50 <br/> * * @author medusar */ public cl

YHJ 7765

转: Linux spinlock_t

我的经验:如果出现死的情况,检查:1. lock 和 unlock是否成对出现了,检查所有的程序分支。2.是否有同时需要2个和2个以上的的情况,避免掉这种情况。3.如果在timer等软中断中出现死,可能是没有使用spin_lock_bh这一类的。reference: http://www.chinaitpower.com/2005September/2005-09-13/200...

weixin_30877181的博客 669

spin_lock, spin_lock_irq, spin_lock_irqsave 的使用场景

Spinlock的目的是用来同步SMP中会被多个CPU同时存取的变量。在Linux中,普通的spinlock由于不带额外的语义,是用起来反而要非常小心。 在Linux kernel中执行的代码大体分normal和interrupt context两种。tasklet/softirq可以归 为normal因为他们可以进入等待;ne sted interrupt是interrupt context

bob_fly1984的专栏 2334

MSComm32.ocx控件注册文件(附详细教程和工具)

串口类应用程序使用必须依赖于MSComm32.ocx控件,如果该控件在系统未注册则无法使用。本文档提供了注册文件并附上附详细教程和一键注册工具。

上一篇: ReentrantLock可重入锁
拓跋竣
博客等级 码龄16年 0粉丝 2原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值