深入解析:自旋锁与互斥量的差异对比

更新:11-18 民间故事 我要投稿 纠错 投诉

互斥锁是一种阻塞锁。当线程无法获取互斥锁时,该线程将被直接挂起。该线程将不再消耗CPU时间。当其他线程释放互斥体时,操作系统将激活挂起的线程。线程并让它运行。

两种类型的锁适用于不同的场景:

如果是多核处理器,如果预计线程等待锁的时间很短,比线程两次切换上下文的时间短,那么使用自旋锁是比较划算的。

如果是多核处理器,并且如果预计线程等待锁的时间较长,至少长于两次线程上下文切换的时间,建议使用互斥锁。

如果是单核处理器,一般建议不要使用自旋锁。因为同一时刻只有一个线程处于运行状态,如果运行的线程发现自己无法获取锁,就只能等待解锁。但由于不挂起,获得锁的线程没有办法进入运行状态,只能等待,直到运行的线程用完操作系统分配给它的时间片,才有机会被调度。在这种情况下使用自旋锁的成本很高。

如果加锁代码经常被调用,但竞争很少发生,则应优先使用自旋锁。自旋锁的成本相对较小,互斥锁的成本较大。

POSIX线程(简称Pthreads)是多核平台上并行编程常用的API。线程同步是并行编程中非常重要的通信方式。最典型的应用是使用Pthreads提供的锁机制(lock)来保护多个线程之间共享的临界区(否则常用的同步机制就是屏障)。

Pthreads 提供了多种锁定机制:

(1)互斥体(mutex):pthread_mutex_***

(2)自旋锁:pthread_spin_***

(3)条件变量:pthread_con_***

(4)读/写锁: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);

从实现原理上来说,Mutex是一种睡眠等待类型的锁。例如,双核机器上有两个线程(线程A和线程B),分别运行在Core0和Core1上。假设线程A想要通过pthread_mutex_lock操作获得临界区锁,而这个锁当前被线程B持有,那么线程A就会被阻塞(blocking),此时Core0会进行一次上下文切换(Context)。 Switch)将线程A放入等待队列中。此时Core0可以运行其他任务(比如另一个线程C),无需忙等待。自旋锁则不然。它是一种忙等待类型的锁。如果线程A使用pthread_spin_lock操作来请求锁,那么线程A将一直忙于等待Core0并不断发出锁请求,直到获得锁。直到。

因此,自旋锁一般用在多核服务器上。

自旋锁

自旋锁有点类似于互斥锁,只不过自旋锁不会导致调用者休眠。如果自旋锁已经被另一个执行单元持有,调用者将继续循环以查看自旋锁的持有者是否已被持有。锁被释放,因此出现术语“自旋”。它的作用是解决某种资源的互斥使用。由于自旋锁不会导致调用者休眠,因此自旋锁比互斥锁效率更高。虽然它比互斥锁更高效,但它也有一些缺点:

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); //如果立即获得锁则返回true,否则立即返回false

释放锁:spin_unlock(x);

将以上内容与以下代码片段结合起来:

spinlock_t 锁; //定义一个自旋锁

spin_lock_init(锁);

自旋锁(锁);

. //关键部分

spin_unlock(锁定); //释放锁

还有一些其他用途:

spin_is_locked(x)

//该宏用于判断自旋锁x是否已被某个执行单元持有(即被锁定)。如果是,则返回true,否则返回false。

自旋解锁等待(x)

//该宏用于等待自旋锁x变得不被任何执行单元持有。如果没有执行单元持有自旋锁,则宏立即返回,否则

//将在那里循环,直到自旋锁被持有者释放。

spin_lock_irqsave(锁,标志)

//该宏获取自旋锁,同时将标志寄存器的值保存到变量flags中并使本地中断无效//.相当于:spin_lock()+local_irq_save()

spin_unlock_irqrestore(锁定,标志)

//该宏释放自旋锁的同时,还将标志寄存器的值恢复为//变量flags中保存的值。它与spin_lock_irqsave 配对。

//相当于:spin_unlock()+local_irq_restore()

spin_lock_irq(锁)

//该宏与spin_lock_irqsave类似,只不过该宏不保存标志寄存器的值。相当于:spin_lock()+local_irq_disable()

spin_unlock_irq(锁定)

//该宏释放自旋锁并启用本地中断。它与spin_lock_irq 结合应用。相当于: spin_unlock()+local_irq+enable()

spin_lock_bh(锁)

//该宏在获取自旋锁的同时使本地软中断无效。相当于: //spin_lock()+local_bh_disable()

spin_unlock_bh(锁定)

//该宏释放自旋锁,同时也使能本地软中断。 //它与spin_lock_bh 配对。相当于:spin_unlock()+local_bh_enable()

spin_trylock_irqsave(锁,标志)

//如果该宏获得了自旋锁,还会将标志寄存器的值保存到变量flags中,并使本地中断无效。如果没有获得锁,则不会执行任何操作。所以如果能立即获得锁,就相当于spin_lock_irqsave,如果不能获得锁,就相当于spin_trylock。如果该宏//获得了自旋锁,则需要使用spin_unlock_irqrestore 来释放它。

spin_trylock_irq(锁)

//该宏与spin_trylock_irqsave类似,只不过该宏不保存标志寄存器。如果该宏获得了自旋锁,则需要使用spin_unlock_irq 来释放它。

spin_trylock_bh(锁)

//如果该宏获得了自旋锁,也会使本地软中断失效。如果它无法获得锁,则//什么也不做。因此,如果获得锁,则相当于spin_lock_bh,如果没有获得锁,则相当于spin_trylock。如果该宏获得了自旋锁,则需要使用spin_unlock_bh 来释放它。

用户评论

oО清风挽发oО

学习C++多线程,这两种锁真是太重要了!

    有16位网友表示赞同!

将妓就计

我感觉自旋锁在轻量级的情况下性能更好吧?

    有9位网友表示赞同!

封锁感觉

互斥量是不是更常见一点?

    有19位网友表示赞同!

暖栀

什么时候应该选择哪种锁啊?没找到一个清晰的标准。

    有16位网友表示赞同!

半世晨晓。

刚开始接触多线程,这两个概念还是很难理解…

    有15位网友表示赞同!

ヅ她的身影若隐若现

这篇文章讲得浅显易懂,很好入门!

    有11位网友表示赞同!

雁過藍天

自旋锁看起来简单很多,但应用场景会不会比较有限呢?

    有7位网友表示赞同!

没过试用期的爱~

Mutex是不是更容易实现啊?

    有20位网友表示赞同!

黑夜漫长

想了解更多关于不同场景下使用哪种锁的案例分析!

    有15位网友表示赞同!

无关风月

这个标题太棒了!点进来刚好可以了解一下区别的原理。

    有7位网友表示赞同!

南宫沐风

感觉互斥量比自旋锁更安全吧?

    有5位网友表示赞同!

_心抽搐到严重畸形っ°

哪个锁更好取决于具体情况啊,没有绝对的好坏。

    有11位网友表示赞同!

半梦半醒半疯癫

学习完这篇文章后,我终于对自旋锁和互斥量有了一个初步的了解!

    有17位网友表示赞同!

厌归人

文章内容非常全面,涵盖了比较关键的知识点。

    有9位网友表示赞同!

醉枫染墨

自旋锁真的比传统方式效率高吗?

    有19位网友表示赞同!

封心锁爱

这篇文章让我觉得多线程编程的可玩性很高!

    有8位网友表示赞同!

败类

学习编程真是充满挑战,但也很有趣啊!

    有7位网友表示赞同!

哭着哭着就萌了°

以后遇到类似的排序问题,应该优先考虑自旋锁吗?

    有5位网友表示赞同!

服从

多线程是未来软件发展的趋势!

    有6位网友表示赞同!

【深入解析:自旋锁与互斥量的差异对比】相关文章:

1.蛤蟆讨媳妇【哈尼族民间故事】

2.米颠拜石

3.王羲之临池学书

4.清代敢于创新的“浓墨宰相”——刘墉

5.“巧取豪夺”的由来--米芾逸事

6.荒唐洁癖 惜砚如身(米芾逸事)

7.拜石为兄--米芾逸事

8.郑板桥轶事十则

9.王献之被公主抢亲后的悲惨人生

10.史上真实张三丰:在棺材中竟神奇复活

上一篇:深入浅出TCP Socket编程基础(Java版) 下一篇:深入解析Rust编程语言(第三部分)