0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

介绍一下Linux内核中的各种锁

嵌入式悦翔园 来源:嵌入式悦翔园 2023-05-16 14:13 次阅读

一、前言

Linux内核中有许多不同类型的锁,它们都可以用来保护关键资源,以避免多个线程或进程之间发生竞争条件,从而保护系统的稳定性和可靠性。这些锁的类型包括:互斥锁(mutex)、读写锁(rwlock)、自旋锁(spinlock)和信号量(semaphore)。今天就给大家介绍一下Linux内核中的各种锁,以及我们在实际项目中该如何选择使用哪个锁。

二、几种锁的介绍

互斥锁(mutex) 是最常用的锁,它可以保护共享资源,使得在某个时刻只有一个线程或进程可以访问它。读写锁(rwlock)则可以同时允许多个线程或进程读取共享资源,但只允许一个线程或进程写入它。自旋锁(spinlock)可以用来保护共享资源,使得在某个时刻只有一个线程或进程可以访问它,但它会使线程或进程“自旋”,直到获得锁为止。最后,信号量(semaphore)可以用来控制对共享资源的访问,以保证其他线程或进程可以安全地访问它们。

读写锁(rwlock) 是一种用于控制多线程访问共享资源的同步机制。当一个线程需要读取共享资源时,可以获取读取锁,这样其他线程就可以同时读取该资源,而不会引发冲突。当一个线程需要写入共享资源时,可以获取写入锁,这样其他线程就不能访问该资源,从而保证数据的完整性和一致性。

自旋锁(spinlock) 是一种简单而有效的用于解决多线程同步问题的锁。它是一种排他锁,可以在多线程环境下保护共享资源,以防止多个线程同时对该资源进行访问。自旋锁的基本原理是,当一个线程试图获取锁时,它会不断尝试获取锁,直到成功为止。在这期间,线程不会进入休眠状态,而是一直处于忙等待(busy-waiting)状态,这也就是自旋锁的由来。

信号量(semaphore) 是一种常用的同步机制,它可以用来控制多个线程对共享资源的访问。它有助于确保同一时间只有一个线程能够访问共享资源,从而避免资源冲突和竞争。信号量是一种整数计数器,用于跟踪可用资源的数量。当一个线程需要访问共享资源时,它首先必须获取信号量,这会将信号量的计数器减少1,而当它完成访问共享资源后,它必须释放信号量,以便其他线程也可以访问共享资源。

四、互斥锁(Mutex)

互斥锁是最基本的锁类型,在内核中使用较为广泛。它是一种二元锁,只能同时有一个线程持有该锁。当一个线程请求该锁时,如果锁已被占用,则线程会被阻塞直到锁被释放。互斥锁的实现使用了原子操作,因此它的性能比较高,但也容易出现死锁情况。

在内核中,互斥锁的定义如下:

structmutex{
raw_spinlock_twait_lock;
structlist_headwait_list;
structtask_struct*owner;
intrecursion;
#ifdefCONFIG_DEBUG_LOCK_ALLOC
structlockdep_mapdep_map;
#endif
};

互斥锁的使用非常简单,通常只需要调用两个函数即可完成:

voidmutex_init(structmutex*lock):函数用于初始化互斥锁
voidmutex_lock(structmutex*lock):函数用于获取互斥锁
voidmutex_unlock(structmutex*lock):函数用于释放互斥锁

五、读写锁(Reader-Writer Lock)

读写锁是一种特殊的锁类型,它允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。读写锁的实现使用了两个计数器,分别记录当前持有锁的读线程数和写线程数。

在内核中,读写锁的定义如下:

structrw_semaphore{
longcount;
structlist_headwait_list;
#ifdefCONFIG_DEBUG_LOCK_ALLOC
structlockdep_mapdep_map;
#endif
};

读写锁的使用也比较简单,通常只需要调用三个函数即可完成:

init_rwsem(struct rw_semaphore *sem):函数用于初始化读写锁
down_read(struct rw_semaphore *sem):函数用于获取读锁
up_read(struct rw_semaphore *sem):函数用于释放读锁
down_write(struct rw_semaphore *sem):函数用于获取写锁
up_write(struct rw_semaphore *sem):函数用于释放写锁

六、自旋锁(spinlock)

自旋锁是一种保护共享资源的锁,它会在等待期间一直占用CPU。自旋锁适用于代码临界区比较小的情况,且共享资源的独占时间比较短,这样就可以避免上下文切换的开销。自旋锁不能用于需要睡眠的代码临界区,因为在睡眠期间自旋锁会一直占用CPU。

在Linux内核中,自旋锁使用spinlock_t类型表示,可以通过spin_lock()和spin_unlock()函数对其进行操作。

spin_lock_init(spinlock_t*lock):用于初始化自旋锁,将自旋锁的初始状态设置为未加锁状态。
spin_lock(spinlock_t*lock):用于获得自旋锁,如果自旋锁已经被占用,则当前进程会自旋等待,直到自旋锁可用。
spin_trylock(spinlock_t*lock):用于尝试获取自旋锁,如果自旋锁当前被占用,则返回0,否则返回1。
spin_unlock(spinlock_t*lock):用于释放自旋锁。

在使用自旋锁时,需要注意以下几点:

自旋锁只适用于临界区代码比较短的情况,因为自旋等待的过程会占用CPU资源。

自旋锁不可重入,也就是说,如果一个进程已经持有了自旋锁,那么它不能再次获取该自旋锁。

在持有自旋锁的情况下,应该尽量避免调用可能会导致调度的内核函数,比如睡眠函数,因为这可能会导致死锁的发生。

在使用自旋锁的时候,应该尽量避免嵌套使用不同类型的锁,比如自旋锁和读写锁,因为这可能会导致死锁的发生。

当临界区代码较长或者需要睡眠时,应该使用信号量或者读写锁来代替自旋锁。

七、信号量(semaphore)

信号量是一种更高级的锁机制,它可以控制对共享资源的访问次数。信号量可分为二元信号量和计数信号量。二元信号量只有0和1两种状态,常用于互斥锁的实现;计数信号量则可以允许多个进程同时访问同一共享资源,只要它们申请信号量的数量不超过该资源所允许的最大数量。

在Linux内核中,信号量使用struct semaphore结构表示,可以通过down()和up()函数对其进行操作。

voidsema_init(structsemaphore*sem,intval):初始化一个信号量,val参数表示初始值。
voiddown(structsemaphore*sem):尝试获取信号量,如果信号量值为0,调用进程将被阻塞。
intdown_interruptible(structsemaphore*sem):尝试获取信号量,如果信号量值为0,调用进程将被阻塞,并可以被中断。
intdown_trylock(structsemaphore*sem):尝试获取信号量,如果信号量值为0,则立即返回,否则返回错误。
voidup(structsemaphore*sem):释放信号量,将信号量的值加 1,并唤醒可能正在等待信号量的进程。

八、该如何选择正确的锁

当需要对共享资源进行访问和修改时,我们通常需要采用同步机制来保证数据的一致性和正确性,其中锁是最基本的同步机制之一。不同类型的锁适用于不同的场景。

互斥锁适用于需要保护共享资源,只允许一个线程或进程访问共享资源的场景。例如,当一个线程正在修改一个数据结构时,其他线程必须等待该线程释放锁后才能修改该数据结构。

读写锁适用于共享资源的读写操作频繁且读操作远大于写操作的场景。读写锁允许多个线程同时读取共享资源,但只允许一个线程写入共享资源。例如,在一个数据库管理系统中,读取操作比写入操作频繁,使用读写锁可以提高系统的并发性能。

自旋锁适用于保护共享资源的访问时间很短的场景,当线程需要等待的时间很短时,自旋锁比互斥锁的性能更好。例如,在访问共享资源时需要进行一些简单的操作,如对共享资源进行递增或递减等操作。

信号量适用于需要协调多个线程或进程对共享资源的访问的场景,允许多个线程或进程同时访问共享资源,但同时访问的线程或进程数量有限。例如,在一个并发下载系统中,可以使用信号量来限制同时下载的文件数量。

举个生活中的例子:当我们在买咖啡的时候,柜台前可能会有一个小桶,上面写着“请取走您需要的糖果,每人一颗”这样的字样。这个小桶就是一个信号量,它限制了每个人能够取走的糖果的数量,从而保证了公平性。

如果我们把这个小桶换成互斥锁,那么就可以只允许一个人在柜台前取走糖果。如果使用读写锁,那么在非高峰期的时候,多个人可以同时取走糖果,但在高峰期时只允许一个人取走。

而如果我们把这个小桶换成自旋锁,那么当有人在取走糖果时,其他人就需要一直在那里等待,直到糖果被取走为止。这样可能会造成浪费时间的情况,因为其他人可能有更紧急的事情需要处理。

九、总结

在Linux内核中,有四种常见的锁:互斥锁、读写锁、自旋锁和信号量。这些锁适用于不同的场景,开发者需要根据实际情况选择适当的锁来确保并发访问的正确性和性能。





审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 计数器
    +关注

    关注

    32

    文章

    2123

    浏览量

    92987
  • LINUX内核
    +关注

    关注

    1

    文章

    311

    浏览量

    21389
  • 信号量
    +关注

    关注

    0

    文章

    53

    浏览量

    8257

原文标题:Linux内核中的互斥锁、读写锁、自旋锁、信号量该如何选择?

文章出处:【微信号:嵌入式悦翔园,微信公众号:嵌入式悦翔园】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Linux内核开发工具介绍

    进行嵌入式Linux产品开发,往往需要对内核进行裁剪和定制,以满足嵌入式产品的功能和性能需求。本文介绍几种阅读Linux内核源码的工具和方法
    发表于 12-29 15:20 4554次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>开发工具<b class='flag-5'>介绍</b>

    Linux 2.6 内核的最新电源管理技术综述

    (包括 kernel、middleware 以及各种用户态 utility)如何添加对这些创新的节能技术的支持这角度,为读者介绍 Linux 操作系统近几年来在电源管理方面所取得的
    发表于 09-28 14:15

    Linux内核开发工具介绍

    款流行度极高的源码阅读和编辑工具。不少Linux开发人员还是习惯于在Windows进行源码编辑,甚至查看和编辑Linux内核源码,依然在Source Insight
    发表于 01-06 17:20

    请问linux内核怎么调试?

    问个问题,怎么调试linux内核,百度了一下,结果还是不会使用gdb调试内核。希望大虾帮忙指点一下
    发表于 02-25 07:32

    Linux内核3.5开发,起了解一下

    1.1 Linux内核模块介绍1.1.1 Linux内核模块概述嵌入式设备驱动开发中将驱动程序以模块的形式发布,更是极大地提高了设备使用的灵
    发表于 10-05 20:36

    Linux内核同步机制的自旋原理是什么?

    自旋是专为防止多处理器并发而引入的,它在内核中大量应用于中断处理等部分(对于单处理器来说,防止中断处理的并发可简单采用关闭中断的方
    发表于 03-31 08:06

    Linux内核自解压过程

      在前面的章节介绍了uboot和Linux内核些相关内容。在来看Linux内核的大致启动流
    发表于 12-29 07:35

    如何使用Linux内核的input子系统

    的 input 子系统提供的 API 函数接口,完成设备的注册即可。在本章节我们来学习一下如何使用 Linux内核
    发表于 12-29 07:20

    请问一下内核的GPIO怎么使用?

    请问一下内核的GPIO怎么使用?
    发表于 09-18 07:03

    使能Linux内核的SCSI协议

    文章目录须知使能U盘U盘测试须知注意, NXP官方的 Linux内核默认已经使能了 U盘!所以我们可以插上直接使用使能U盘虽然可以直接使用,但是我们还是要学习一下如何手动配置Linux
    发表于 12-16 06:27

    linux 5.4.31为例来介绍一下linux内核目录结构

    ,它是Linux内核的概述和编译命令说明。readme的说明更加针对X86等通用的平台,对于某些特殊的体系结构,可能有些特殊的地方。内核源码很复杂,包含多级目录,形成个庞大的树状结构
    发表于 02-16 07:30

    记录一下Linux设备模型学习历程

    Linux设备模型学习笔记1KobjectKobject, Kset和KtypeUeventsysfs文件系统wowo这里写的很好了:内核等看wowo写的很有帮助我写一下我的理解。记录一下
    发表于 02-17 06:05

    介绍一下Linux内核编译和更新的操作流程

    。由于官方没有提高最新Linux内核版本的烧写固件,为了解决些比较严重的bug,需要自行编译Linux内核进行更新,接下来就
    发表于 06-21 09:58

    【学习打卡】OpenHarmony的linux内核介绍

    。大多数云解决方案提供商,包括亚马逊网络服务和谷歌云平台,都依赖Linux和开源解决方案。如果个进程在用户模式失败,损害是有限的,可以由内核恢复。但是,由于它对内存和处理器的访问,
    发表于 07-22 18:26

    小编科普一下Linux内核中常用的C语言技巧

    Linux内核采用的是GCC编译器,GCC编译器除了支持ANSI C,还支持GNU C。在Linux内核中,许多地方都使用了GNU C语言的扩展特性,如typeof、__attribu
    的头像 发表于 02-08 11:51 508次阅读