iis服务器助手广告广告
返回顶部
首页 > 资讯 > 操作系统 >如何理解Linux驱动中内核互斥锁
  • 193
分享到

如何理解Linux驱动中内核互斥锁

2023-06-15 21:06:43 193人浏览 八月长安
摘要

如何理解linux驱动中内核互斥锁,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 互斥体概述信号量是在并行处理环境中对多个处理器访问某个公共资源进行保护的机制,mut

如何理解linux驱动中内核互斥,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

 

互斥体概述

信号量是在并行处理环境中对多个处理器访问某个公共资源进行保护的机制,mutex用于互斥操作。信号量的count初始化为1,down()/up()也可以实现类似mutex的作用。

mutex的语义相对于信号量要简单轻便一些,在锁争用激烈的测试场景下,mutex比信号量执行速度更快,可扩展性更好,另外mutex数据结构的定义比信号量小。

mutex的优点

  1. mutex和信号量相比要高效的多:

  2. mutex最先实现自旋等待机制

  3. mutex在睡眠之前尝试获取锁

  4. mutex实现MCS所来避免多个CPU争用锁而导致CPU高速缓存颠簸现象。

mutex的使用注意事项:

  1. 同一时刻只有一个线程可以持有mutex。

  2. 只有锁持有者可以解锁。不能再一个进程中持有mutex,在另外一个进程中释放他。

  3. 不允许递归地加锁和解锁。

  4. 当进程持有mutex时,进程不可以退出。

  5. mutex必须使用官方api来初始化。

  6. mutex可以睡眠,所以不允许在中断处理程序或者中断下半部中使用,例如tasklet、定时器等。

目录:

/linux/include/linux/mutex.h   struct mutex {      atomic_t    count;   spinlock_t    wait_lock;   struct list_head  wait_list; #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP)   struct task_struct  *owner; #endif #ifdef CONFIG_MUTEX_SPIN_ON_OWNER   void      *spin_mlock;   #endif #ifdef CONFIG_DEBUG_MUTEXES   const char     *name;   void      *magic; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC   struct lockdep_map  dep_map; #endif };

作用及访问规则:

  1. 互斥锁主要用于实现内核中的互斥访问功能。内核互斥锁是在原子 API 之上实现的,但这对于内核用户是不可见的。

  2. 对它的访问必须遵循一些规则:同一时间只能有一个任务持有互斥锁,而且只有这个任务可以对互斥锁进行解锁。互斥锁不能进行递归锁定或解锁。一个互斥锁对象必须通过其API初始化,而不能使用memset或复制初始化。一个任务在持有互斥锁的时候是不能结束的。互斥锁所使用的内存区域是不能被释放的。使用中的互斥锁是不能被重新初始化的。并且互斥锁不能用于中断上下文。

  3. 互斥锁比当前的内核信号量选项更快,并且更加紧凑。

互斥体的使用

初始化

静态定义如下:

DEFINE_MUTEX(name);

动态初始化mutex,如下:

mutex_init(&mutex);

具体实现如下:

#define mutex_init(mutex) \ do {       \  static struct lock_class_key __key;  \        \  __mutex_init((mutex), #mutex, &__key);  \ } while (0)  void __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) {  atomic_set(&lock->count, 1);  spin_lock_init(&lock->wait_lock);  INIT_LIST_HEAD(&lock->wait_list);  mutex_clear_owner(lock); #ifdef CONFIG_MUTEX_SPIN_ON_OWNER  lock->spin_mlock = NULL; #endif   debug_mutex_init(lock, name, key); }

申请互斥锁

mutex操作列表如下:

方法描述
mutex_lock(struct mutex*)为指定的mutex上锁,如果不可用则睡眠
mutex_unlock(struct mutex*)为指定的mutex解锁
mutex_trylock(struct mutex*)视图获取指定的mutex,如果成功则返回1;否则锁被获取,返回值是0
mutex_is_lock(struct mutex*)如果锁已被征用,则返回1;否则返回0

mutex的简洁性和高效性源自于相比使用信号量更多的受限性。它不同于信号量,因为mutex仅仅实现了Dijkstra设计初衷中的最基本的行为。因此mutex的使用场景相对而言更严格。

(1)代码:linux/kernel/mutex.c

void inline fastcall __sched mutex_lock(struct mutex *lock);     //获取互斥锁。

实际上是先给count做自减操作,然后使用本身的自旋锁进入临界区操作。首先取得count的值,在将count置为-1,判断如果原来count的置为1,也即互斥锁可以获得,则直接获取,跳出。否则进入循环反复测试互斥锁的状态。在循环中,也是先取得互斥锁原来的状态,在将其之为-1,判断如果可以获取(等于1),则退出循环,否则设置当前进程的状态为不可中断状态,解锁自身的自旋锁,进入睡眠状态,待被在调度唤醒时,再获得自身的自旋锁,进入新一次的查询其自身状态(该互斥锁的状态)的循环。

(2)具体参见linux/kernel/mutex.c

int fastcall __sched mutex_lock_interruptible(struct mutex *lock);

和mutex_lock()一样,也是获取互斥锁。在获得了互斥锁或进入睡眠直到获得互斥锁之后会返回0。如果在等待获取锁的时候进入睡眠状态收到一个信号(被信号打断睡眠),则返回_EINIR。

(3)具体参见linux/kernel/mutex.c

int fastcall __sched mutex_trylock(struct mutex *lock);

试图获取互斥锁,如果成功获取则返回1,否则返回0,不等待。

释放互斥锁

具体参见linux/kernel/mutex.c

void fastcall mutex_unlock(struct mutex *lock);

释放被当前进程获取的互斥锁。该函数不能用在中断上下文中,而且不允许去释放一个没有上锁的互斥锁。

互斥锁试用注意事项

  1. 任何时刻中只有一个任务可以持有mutex, 也就是说,mutex的使用计数永远是1

  2. 给mutex锁者必须负责给其再解锁——你不能在一个上下文中锁定一个mutex,而在另  一个上下文中给它解锁。这个限制使得mutex不适合内核同用户空间复杂的同步场景。最 常使用的方式是:在同一上下文中上锁和解锁。

  3. 递归地上锁和解锁是不允许的。也就是说,你不能递归地持有同一个锁,同样你也不能再去解锁一个已经被解开的mutex

  4. 当持有一个mutex时 ,进程不可以退出

  5. mutex不能在中断或者下半部中使用,即使使用mutex_trylock()也不行

  6. mutex只能通过官方API管理:它只能使用上节中描述的方法初始化,不可被拷贝、手动 初始化或者重复初始化

信号量和互斥体

互斥体和信号量很相似,内核中两者共存会令人混淆。所幸,它们的标准使用方式都有简单规范:除非mutex的某个约束妨碍你使用,否则相比信号量要优先使用mutex。当你写新代码时,只有碰到特殊场合(一般是很底层代码)才会需要使用信号量。因此建议  选mutex。如果发现不能满足其约束条件,且没有其他别的选择时,再考虑选择信号量

自旋锁和互斥体使用场合

了解何时使用自旋锁,何时使用互斥体(或信号量)对编写优良代码很重要,但是多数情况下,并不需要太多的考虑,因为在中断上下文中只能使用自旋锁,而在任务睡眠时只能使用互斥体。

下面总结一下各种锁的需求情况

需求建议的加锁方法
低开销加锁优先使用自旋锁
短期锁定优先使用自旋锁
长期锁定优先使用互斥体
中断上下文中加锁使用自旋锁
持有锁需要睡眠使用互斥体

互斥锁锁定和解锁使用实例

使用方法如下:

1. struct mutex mutex; 2. mutex_init(&mutex);  3. //加锁 4. mutex_lock(&mutex); 5.   6. //临界区 7.  8. //解锁 9. mutex_unlock(&mutex);

可以看出,互斥体就是一个简化版的信号量,因为不再需要管理任何使用计数。

下面网卡DM9000的驱动,其中写入eeprom的操作试用了mutex机制:

static void dm9000_write_eeprom(board_info_t *db, int offset, u8 *data) {  unsigned long flags;   if (db->flags & DM9000_PLATF_NO_EEPROM)   return;   mutex_lock(&db->addr_lock);   spin_lock_irqsave(&db->lock, flags);  iow(db, DM9000_EPAR, offset);  iow(db, DM9000_EPDRH, data[1]);  iow(db, DM9000_EPDRL, data[0]);  iow(db, DM9000_EPCR, EPCR_WEP | EPCR_ERPRW);  spin_unlock_irqrestore(&db->lock, flags);   dm9000_wait_eeprom(db);   mdelay(1);    spin_lock_irqsave(&db->lock, flags);  iow(db, DM9000_EPCR, 0);  spin_unlock_irqrestore(&db->lock, flags);   mutex_unlock(&db->addr_lock); }

可以看到每次驱动向eeprom写入数据(访问临界资源),都需要首先获得该资源对应的互斥锁db->addr_lock,并且使用完毕必须释放该锁。

看完上述内容,你们掌握如何理解Linux驱动中内核互斥锁的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注编程网操作系统频道,感谢各位的阅读!

--结束END--

本文标题: 如何理解Linux驱动中内核互斥锁

本文链接: https://www.lsjlt.com/news/281610.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何理解Linux驱动中内核互斥锁
    如何理解Linux驱动中内核互斥锁,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。 互斥体概述信号量是在并行处理环境中对多个处理器访问某个公共资源进行保护的机制,mut...
    99+
    2023-06-15
  • 如何理解Linux内核驱动的编码风格
    本篇文章给大家分享的是有关如何理解Linux内核驱动的编码风格,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代...
    99+
    2023-06-16
  • Linux内核设备驱动之内核中链表的使用笔记整理
    (1)介绍 在linux内核中使用了大量的链表结构来组织数据,包括设备列表以及各种功能模块中的数据组织。这些链表大多采用在include/linux/list.h实现的一个相当精彩的链表数据结构。 链表数据结构的...
    99+
    2022-06-04
    linux内核中链表的使用 linux内核设备驱动
  • 如何理解Go里面的互斥锁mutex
    如何理解Go里面的互斥锁mutex,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1. 锁的基础概念1.1 CAS与轮询1.1.1 cas实现锁 在锁的实现中现在越来越多的采用C...
    99+
    2023-06-19
  • 如何理解Linux内核中Watchdog
    这期内容当中小编将会给大家带来有关如何理解Linux内核中Watchdog,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。在Linux内核中有三个watchdog,它们都需要被悉心的喂养照料,分别是: /d...
    99+
    2023-06-15
  • 如何理解Linux内核编译
    这篇文章给大家介绍如何理解Linux内核编译,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一、前言(仅供参考)linux内核该如何学习安装vmware虚拟机或者virtualbox,再安装发行版本linuxwww.ke...
    99+
    2023-06-15
  • 如何理解互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景
    本篇内容主要讲解“如何理解互斥锁、自旋锁、读写锁、悲观锁、乐观锁的应用场景”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何理解互斥锁、自旋锁、读写锁、悲观锁、...
    99+
    2022-10-18
  • 如何理解Linux内核信号量
    本篇文章给大家分享的是有关如何理解Linux内核信号量,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。概念Linux内核的信号量在概念和原理上和用户态的System V的IPC机...
    99+
    2023-06-15
  • 如何理解Linux内核的文件
    本篇内容介绍了“如何理解Linux内核的文件”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Linux文件预读算法磁盘I/O性能的发展远远滞后...
    99+
    2023-06-13
  • Linux内核中的数据双链表如何理解
    这篇文章给大家介绍Linux内核中的数据双链表如何理解,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Linux 内核中自己实现了双向链表,可以在 include/linux/list.h 找到定义。我们将会首...
    99+
    2023-06-28
  • 如何理解linux内核的软中断的情况
    这篇文章主要讲解了“如何理解linux内核的软中断的情况”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解linux内核的软中断的情况”吧!软中断介绍把可以延迟的处理从硬中断处理程序独立...
    99+
    2023-06-13
  • 如何理解Linux内核参数overcommit_memory和OOM killer
    如何理解Linux内核参数overcommit_memory和OOM killer,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。什么是Linux Overcommit和OOMo...
    99+
    2023-06-05
  • 如何解析Linux系统架构中的内核
    如何解析Linux系统架构中的内核,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。概述Linux系统一般有4个主要部分组成,内核、shell、文件系统和应用程序。内核、shell...
    99+
    2023-06-16
  • 如何解析Linux驱动中的platform总线
    如何解析Linux驱动中的platform总线,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。1、platform 总线简介1.1、Linux 驱动的分离和分层思...
    99+
    2023-06-22
  • Java+Linux内核源码之如何理解多线程之进程
    这篇文章主要讲解了“Java+Linux内核源码之如何理解多线程之进程”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java+Linux内核源码之如何理解多线程之进程”吧!Linux 内核如...
    99+
    2023-06-15
  • Linux内核如何打造WWAN子系统以发展通用驱动并加强扩展能力
    本篇文章给大家分享的是有关Linux内核如何打造WWAN子系统以发展通用驱动并加强扩展能力,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Linaro继续领导Linux内核的无线...
    99+
    2023-06-15
  • 测试驱动技术系列之如何理解操控excel的核心api
    这篇文章主要讲解了“测试驱动技术系列之如何理解操控excel的核心api”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“测试驱动技术系列之如何理解操控excel的核心api”吧!测试数据格式展...
    99+
    2023-06-15
  • Linux设备驱动指的定时与延时如何理解
    本篇文章为大家展示了Linux设备驱动指的定时与延时如何理解,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Linux通过系统硬件定时器以规律的间隔(由HZ度量)产生定时器中断,每次中断使得一个内核计...
    99+
    2023-06-16
  • 如何理解Linux内核及其相关架构的依赖关系
    这篇文章主要介绍“如何理解Linux内核及其相关架构的依赖关系”,在日常操作中,相信很多人在如何理解Linux内核及其相关架构的依赖关系问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Linux内核及其...
    99+
    2023-06-12
  • 深入理解Linux网络——内核是如何接收到网络包的
    文章目录 一、相关实际问题二、数据是如何从网卡到协议栈的1、Linux网络收包总览2、Linux启动1)创建ksotfirqd内核线程2)网络子系统初始化3)协议栈注册4)网卡驱动初始化5)网...
    99+
    2023-09-06
    网络 linux tcp/ip 网卡 网络协议
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作