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

前面对互斥锁Monitor进行了详细学习,今天我们将继续学习,一种更轻量级的锁——自旋锁SpinLock。

今日霍州(www.jrhz.info)©️

在 C# 中,SpinLock是一个高效的自旋锁实现,用于提供一种轻量级的锁机制。SpinLock通过在等待锁的过程中执行自旋(即不断尝试获取锁)来避免线程上下文切换,从而减少系统开销。

今日霍州(www.jrhz.info)©️

SpinLock是一个结构体,使用上和Monitor类很像,都是通过Enter或TryEnter方法持有锁,同时默认支持lockTaken模式,然后通过Exit释放锁。

01、使用示例

下面我们通过启动10个线程,使用SpinLock锁分别递增共享变量_counter,最后再打印出共享变量_counter,代码如下:

今日霍州(www.jrhz.info)©️

不用看也可以预测出结果为10,执行结果如下:

今日霍州(www.jrhz.info)©️

另外TryEnter方法也和Monitor类同样支持设置超时时间。

02、小心传递SpinLock实例

在传递SpinLock实例时,需要十分小心,这是因为SpinLock是结构体即为值类型,当通过值传递,会导致创建该结构体的副本,复制一个新的实例,而不是传递引用。

如下示例代码:

今日霍州(www.jrhz.info)©️

这段代码有两个问题是:

1.方法Method1的两次调用中的lockCopy是各不相同的锁,即会导致两次调用都能获取到锁;

2.方法Method1中的lockCop和主方法中spinLock是两个不同的锁,会导致主方法释放锁异常;

我们可以看看代码执行结果:

今日霍州(www.jrhz.info)©️

方法两次调用都成功获取锁,同时最后释放锁时抛出了异常。和我们上面说的两个问题完全一致。

而要解决这个问题也很简单,只需要把Method1方法的SpinLock参数前加上ref即可。代码如下:

今日霍州(www.jrhz.info)©️

执行结果如下:

今日霍州(www.jrhz.info)©️

从结果上可以发现Method中和主方法中的SpinLock锁都是同一个了。

03、实现原理

从上面代码可以发现从使用上来说,SpinLock和互斥锁Monitor基本一样,那为什么还要SpinLock呢?

首先互斥锁Monitor在获取锁时会阻塞线程,同时线程会进行上下文切换,把CPU资源让出来给其他线程使用,直到锁可用。从这里也可以看出互斥锁Monitor适用锁竞争时间较长的场景,否则线程上下文切换比等待资源消耗代价更高就不划算了。

针对上面提到的问题,就引发了需要一种非阻塞线程的锁方案,因此SpinLock就应用而生。

如何实现非阻塞线程呢?

首先我们需要理解非阻塞的意义,它是为了解决进行线程上下文切换的代价比锁的等待代价更大的问题。说白了就是不要让线程进行上下文切换,比如最简单粗暴的方式就是直接使用while(true){},使得线程一直处于活动状态。

而SpinLock底层实现原理的确通过使用while(true){},使得线程原地停留且又不阻塞线程。因为while(true)自动循环的特点才叫自旋锁。当然SpinLock底层实现不止这么简单,比如还用到了原子操作Interlocked.CompareExchange。

总结下来SpinLock 的工作原理,大致分为以下两步:

1.当前线程尝试获取锁,如果获取成功,进入同步代码块。

2.如果未能取锁(即锁已经被另一个线程持有),则当前线程会在一个循环(自旋)中重复尝试,直到获取到锁。

SpinLock主要优势在于它不会将线程挂起即不会发生线程上下文切换,而是让线程在一个循环(自旋)中等待,直到锁被释放后再获取。同样因为线程一直自旋等待,如果线程需要等待时间很长又会导致CPU占用过高以及资源浪费。

结合SpinLock实现原理,有如下建议:

1.在需要大量锁(高并发)并且锁持有时间又非常短的场景下,特别适合使用SpinLock。

2.避免在单核CPU上使用SpinLock,因为自旋等待会浪费CPU资源。

04、实现一个简单的自旋锁

下面我们可以根据SpinLock实现原理来自己实现一个简单的自旋锁。

大致思路如下:

1.通过在while(true)循环中,使用原子操作Interlocked.CompareExchange进行设置锁,从而实现持有锁方法Enter;

2.通过直接标记锁状态为未锁定状态,来实现锁释放方法Exit;

具体代码如下:

今日霍州(www.jrhz.info)©️

然后把使用示例中的代码SpinLock替换为MySpinLock即可验证我们自己的自旋锁实现,运行结果如下,基本和原生的SpinLock功能一致。

今日霍州(www.jrhz.info)©️

特别声明:[并发编程 - 线程同步(八)之自旋锁SpinLock] 该文观点仅代表作者本人,今日霍州系信息发布平台,霍州网仅提供信息存储空间服务。

猜你喜欢

可怜之人必有可恨之处?『张柏芝』自曝被朋友背叛,原来一切早有预兆(可怜之人必有可恨之处真正的意思)

『张柏芝』曾在节目中自述屡遭朋友背叛,如今看来,一切或许早有伏笔,世间之事,果然皆有来由。不知是否早有规划,『张柏芝』似乎想借助这档风头正劲的节目,一举扭转外界对她固有的“负面”印象。 『张柏芝』说,自己童年时其实非常…

可怜之人必有可恨之处?『张柏芝』自曝被朋友背叛,原来一切早有预兆(可怜之人必有可恨之处真正的意思)

酒水防伪追溯:消费者查询便捷方式(酒业 防伪)

随着技术的发展,酒水行业采用多种方法实现产品防伪和追溯,消费者可以通过便捷方式查询产品真伪。在进行防伪查询时,消费者应注意以下几点:首先,确保使用官方提供的查询渠道,避免通过非正规途径泄露信息。 总之,酒水…

酒水防伪追溯:消费者查询便捷方式(酒业 防伪)

寒潮来了高端羽绒成街头主流,打工人抱紧黑色排骨龟壳,溢价与保暖该怎么选?(寒潮来袭什么意思)

眼看着羽绒服的时尚潮正劲,越来越多品牌开始布局羽绒服跨界,即便是一万元的始祖鸟羽绒服,也有上百人付款,三千元左右的北面羽绒服,更是街头撞衫率极高的单品,数据显示高档羽绒服(1500元以上)的市场占比超三成,看…

寒潮来了高端羽绒成街头主流,打工人抱紧黑色排骨龟壳,溢价与保暖该怎么选?(寒潮来袭什么意思)

46岁『李晨』公园被偶遇,引得一群大妈热情围观,魅力还是不减当年(『李晨』ego)

他已经46岁了,但走在公园里与一群中年人并肩而行时,整个人依旧充满青春气息,状态保持得非常好,完全看不出岁数。 更让人意外的是,当天『李晨』在公园里吸引了大批大妈大爷围观,场面热闹得几乎水泄不通。这个角色让『李晨』…

46岁『李晨』公园被偶遇,引得一群大妈热情围观,魅力还是不减当年(『李晨』ego)

家里家外2》:在爽感与真实间拉扯,在信念与隐忧间平衡(家里家外2什么时候播)

在《家2》中,“用家里的真对抗家外的假,用家里的暖抵御家外的寒”“不论时代如何变化,只要家人还在,爱就一直在”之类既温情又催泪的句子以画外音的形式不断点题,将习惯了“宅斗”爽感的短剧观众带上了一条新赛道。 我…

《<strong>家里家外2</strong>》:在爽感与真实间拉扯,在信念与隐忧间平衡(家里家外2什么时候播)