自旋锁和互斥锁区别在哪_互斥锁的实现

自旋锁和互斥锁区别在哪_互斥锁的实现POSIXthreads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API。线程同步(ThreadSynchronization)是并行编程中非常重要的通讯手段,其中最典型的应用就是用Pthreads提供的锁机制(lock)来对多个线程之间共享的临界区(CriticalSection)进行保护(另一种常用的同步机制是barrier)。Pthreads提供了多种锁机制:…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常用的API。线程同步(Thread Synchronization)是并行编程中非常重要的通讯手段,其中最典型的应用就是用Pthreads提供的锁机制(lock)来对多个线程之间共 享的临界区(Critical Section)进行保护(另一种常用的同步机制是barrier)。

Pthreads提供了多种锁机制:
(1) Mutex(互斥量):pthread_mutex_***
(2) Spin lock(自旋锁):pthread_spin_***
(3) Condition Variable(条件变量):pthread_con_***
(4) Read/Write lock(读写锁):pthread_rwlock_***

Pthreads提供的Mutex锁操作相关的API主要有:
pthread_mutex_lock (pthread_mutex_t *mutex);
pthread_mutex_trylock (pthread_mutex_t *mutex);
pthread_mutex_unlock (pthread_mutex_t *mutex);

Pthreads提供的与Spin Lock锁操作相关的API主要有:
pthread_spin_lock (pthread_spinlock_t *lock);
pthread_spin_trylock (pthread_spinlock_t *lock);
pthread_spin_unlock (pthread_spinlock_t *lock);

曾经有个经典的例子来比喻自旋锁:A,B两个人合租一套房子,共用一个厕所,那么这个厕所就是共享资源,且在任一时刻最多只能有一个人在使用。当厕所闲置时,谁来了都可以使用,当A使用时,就会关上厕所门,而B也要使用,但是急啊,就得在门外焦急地等待,急得团团转,是为“自旋”,呵呵。这个比喻还算恰当吧,大家也明白为什么要求锁的持有时间尽量短了吧!A B 相当于 cpu 内核,厕所就相当于互斥资源。

从 实现原理上来讲,Mutex属于sleep-waiting类型的锁。例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和 Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程A就会被阻塞 (blocking),Core0 会在此时进行上下文切换(Context Switch)将线程A置于等待队列中,此时Core0就可以运行其他的任务(例如另一个线程C)而不必进行忙等待。而Spin lock则不然,它属于busy-waiting类型的锁,如果线程A是使用pthread_spin_lock操作去请求锁,那么线程A就会一直在 Core0上进行忙等待并不停的进行锁请求,直到得到这个锁为止。自旋锁 本来就只是一个很简单的同步机制,在 SMP 之前根本就没这个东西,一切都是 Event 之类的同步机制,这类同步机制都有一个共性就是 一旦资源被占用都会产生任务切换,任务切换涉及很多东西的(保存原来的上下文,按调度算法选择新的任务,恢复新任务的上下文,还有就是要修改cr3寄存器会导致cache失效)这些都是需要大量时间的,因此用 Event 之类来同步一旦涉及到阻塞代价是十分昂贵的,比如 我用一个Event来控制2行代码的原子操作  这个时候一个CPU正在执行这个代码  另一个CPU也要进入  另一个CPU就会产生任务切换  为了短短的两行代码 就进行任务切换执行大量的代码  对系统性能不利 另一个CPU还不如直接有条件的死循环 等待那个CPU把那两行代码执行完

这也就是为什么自旋锁 要调整运行级别  因为另一个CPU可能在死循环不干活  自己必须快点执行完  要快点执行完  就必须保证自己的原子性  因此提高权限关闭中断是必须的

其实windows的自旋锁机制还是很简单的了  linux更复杂  linux提供了更多自旋锁操作方式 尤其是对中断中使用自旋锁的情况  当然一般是不提倡中断中使用自旋锁的 

 

所以,自旋锁一般用用多核的服务器。 

 

自旋锁(Spin lock)

自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是 否该自旋锁的保持者已经释放了锁,”自旋”一词就是因此而得名。其作用是为了解决某项资源的互斥使用。因为自旋锁不会引起调用者睡眠,所以自旋锁的效率远 高于互斥锁。虽然它的效率比互斥锁高,但是它也有些不足之处:
    1、自旋锁一直占用CPU,他在未获得锁的情况下,一直运行--自旋,所以占用着CPU,如果不能在很短的时 间内获得锁,这无疑会使CPU效率降低。
    2、在用自旋锁时有可能造成死锁,当递归调用时有可能造成死锁,调用有些其他函数也可能造成死锁,如 copy_to_user()、copy_from_user()、kmalloc()等。
因此我们要慎重使用自旋锁,自旋锁只有在内核可抢占式或SMP的情况下才真正需要,在单CPU且不可抢占式的内核下,自旋锁的操作为空操作。自旋锁适用于锁使用者保持锁时间比较短的情况下。
       自旋锁的用法如下:
   首先定义:spinlock_t x;
 然后初始化:spin_lock_init(spinlock_t *x);   //自旋锁在真正使用前必须先初始化
 在2.6.11内核中将定义和初始化合并为一个宏:DEFINE_SPINLOCK(x)
    
  获得自旋锁:spin_lock(x);   //只有在获得锁的情况下才返回,否则一直“自旋”
                           spin_trylock(x);  //如立即获得锁则返回真,否则立即返回假
      释放锁:spin_unlock(x);
    
结合以上有以下代码段:

    spinlock_t lock;        //定义一个自旋锁
    spin_lock_init(&lock);
    spin_lock(&lock);    
    …….        //临界区
    spin_unlock(&lock);   //释放锁
    
    还有一些其他用法:
spin_is_locked(x)
    //  该宏用于判断自旋锁x是否已经被某执行单元保持(即被锁),如果是,   返回真,否则返回假。
spin_unlock_wait(x)
    //  该宏用于等待自旋锁x变得没有被任何执行单元保持,如果没有任何执行单元保持该自旋锁,该宏立即返回,否
    //将循环    在那里,直到该自旋锁被保持者释放。

spin_lock_irqsave(lock, flags)
    //  该宏获得自旋锁的同时把标志寄存器的值保存到变量flags中并失效本地中//断。相当于:spin_lock()+local_irq_save()
spin_unlock_irqrestore(lock, flags)
    //  该宏释放自旋锁lock的同时,也恢复标志寄存器的值为变量flags保存的//值。它与spin_lock_irqsave配对使用。
    //相当于:spin_unlock()+local_irq_restore()

spin_lock_irq(lock)
     //该宏类似于spin_lock_irqsave,只是该宏不保存标志寄存器的值。相当         //于:spin_lock()+local_irq_disable()
spin_unlock_irq(lock)
    //该宏释放自旋锁lock的同时,也使能本地中断。它与spin_lock_irq配对应用。相当于: spin_unlock()+local_irq+enable()

spin_lock_bh(lock)
    //  该宏在得到自旋锁的同时失效本地软中断。相当于:  //spin_lock()+local_bh_disable()
spin_unlock_bh(lock)
      //该宏释放自旋锁lock的同时,也使能本地的软中断。它与spin_lock_bh配对//使用。相当于:spin_unlock()+local_bh_enable()

spin_trylock_irqsave(lock, flags)
    //该宏如果获得自旋锁lock,它也将保存标志寄存器的值到变量flags中,并且失//效本地中断,如果没有获得锁,它什么也不做。因此如果能够立即 获得锁,它等//同于spin_lock_irqsave,如果不能获得锁,它等同于spin_trylock。如果该宏//获得自旋锁lock,那需要 使用spin_unlock_irqrestore来释放。

spin_trylock_irq(lock)
    //该宏类似于spin_trylock_irqsave,只是该宏不保存标志寄存器。如果该宏获得自旋锁lock,需要使用spin_unlock_irq来释放。
spin_trylock_bh(lock)
    //  该宏如果获得了自旋锁,它也将失效本地软中断。如果得不到锁,它什么//也不做。因此,如果得到了锁,它等同于spin_lock_bh,如果得 不到锁,它等同//于spin_trylock。如果该宏得到了自旋锁,需要使用spin_unlock_bh来释放。
spin_can_lock(lock)
    //  该宏用于判断自旋锁lock是否能够被锁,它实际是spin_is_locked取反。//如果lock没有被锁,它返回真,否则,返回 假。该宏在2.6.11中第一次被定义,在//先前的内核中并没有该宏。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/200858.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • armv7是什么处理器_originos有几个版本

    armv7是什么处理器_originos有几个版本这两天遇到静态库不支持armv7s的问题,所以顺道了解和总结一下几个arm架构的一些基本区别。 ARM是微处理器行业的一家知名企业,arm处理器以体积小和高性能的优势在嵌入式设备中广泛使用,几乎所有手机都是使用它的。armv6,armv7,armv7s,arm64是ARMCPU的不同指令集,原则上是向下兼容的。如iPhone4SCPU支持armv7,但它同时兼

  • NSGA2算法代码理解

    NSGA2算法代码理解NSGA2算法代码理解:设置200个个体,目标函数为2个,决策变量的个数为30,首先初始化得到一个每个个体位于0~1之间的决策变量,利用ZDT1函数求得目标值,保存在数组中。寻找非支配排序,在这200个个体中,选中一个个体,将这个个体和其余个体的目标函数值比较,如果没有一个个体可以支配他,那么就将其加入到非支配集合中ifindividual(i).n==0%个体i非支配等级排序最高,…

  • strftime函数

    strftime函数strftime函数用于接收时间元组,并返回以可读字符串表示的当地时间,格式由参数format决定(格式参数在本章前一节有详细介绍)。例如:01#!/usr/bin/envpython02#–coding:UTF-8–0304importtime0506t=(2018,7,17,17,3,1,1,1,0)07t=time.mktime(t)08print(time.strftime(“%b%d%Y%H:%M:%S”,time.gmtime(t)))执行结果如下:Jul

    2022年10月21日
  • 如何查看某个端口被谁占用

    如何查看某个端口被谁占用

  • sdram控制器设计

    sdram控制器设计SDRAM控制器

  • activiti 生命周期_activiti教程

    activiti 生命周期_activiti教程activiti工作流的web流程设计器整合视频教程SSM和独立部署本视频为activiti工作流的web流程设计器整合视频教程整合Acitiviti在线流程设计器(Activiti-Modeler5.21.0官方流程设计器)本视频共讲了两种整合方式1.流程设计器和其它工作流项目分开部署的方式2.流程设计器和SSM框架项目整合在一起的方式视频大小…文章风火轮12017-04-0511…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号