两个 app 应用程序之间对共享资源的竞争访问引起了数据传输错误, 而在 Linux 内核中, 提供了四种处理并发与竞争的常见方法:
分别是原子操作、 自旋锁、 信号量、 互斥体, 这里了解下原子操作
前面了解了自旋锁,这里重点看自旋锁死锁问题了解、分析。
文章目录
参考资料
前面了解了原子操作和自旋锁,当然还有之前的字符设备相关操作,前面基础知识还是需要重点掌握的,才能将知识点串联起来:
接下来还是以前面字符设备 动态参数传递实验为基础,打开访问字符设备实验。 所以以前知识点 建议了解
在字符设备这块内容,所有知识点都是串联起来的,需要整体来理解,缺一不可,建议多了解一下基础知识
驱动-申请字符设备号
驱动-注册字符设备
驱动-创建设备节点
驱动-字符设备驱动框架
驱动-杂项设备
驱动-内核空间和用户空间数据交换
驱动-文件私有数据
Linux驱动之 原子操作
Linux驱动—原子操作
驱动-自旋锁
自旋锁死锁 概念
死锁是指两个或多个事物在同一资源上相互占用, 并请求锁定对方的资源, 从而导致恶性循环的现象。 当多个进程因竞争资源而造成的一种僵局(互相等待) , 若无外力作用, 这些进程都将无法向前推进, 这种情况就是死锁。
自旋锁死锁发生存在两种情况:
-
第一种情况是拥有自旋锁的进程 A 在内核态阻塞了, 内核调度 B 进程, 碰巧 B 进程也要获得自旋锁, 此时 B 只能自旋转。 而此时抢占已经关闭(在单核条件下)不会调度 A 进程了,B 永远自旋, 产生死锁

相应的解决办法是, 在自旋锁的使用过程中要尽可能短的时间内拥有自旋锁, 而且不能在临界区中调用导致线程休眠的函数 -
第二种情况是进程 A 拥有自旋锁, 中断到来, CPU 执行中断函数, 中断处理函数, 中断处理函数需要获得自旋锁, 访问共享资源, 此时无法获得锁, 只能自旋, 从而产生死锁

对于中断引发的死锁, 最好的解决方法就是在获取锁之前关闭本地中断
这里从概念上面理解,尝试思考死锁情况。
自旋锁死锁的常见原因
递归锁定
spin_lock(&lock);
spin_lock(&lock); // 第二次尝试获取已持有的锁,导致死锁
中断上下文与进程上下文竞争
// 进程上下文
spin_lock(&lock);
// 中断处理程序
spin_lock(&lock); // 如果中断发生在进程持有锁时,导致死锁
锁顺序不一致
// 线程A
spin_lock(&lock1);
spin_lock(&lock2);
// 线程B
spin_lock(&lock2);
spin_lock(&lock1); // 可能导致死锁
长时间持有自旋锁
spin_lock(&lock);
msleep(1000); // 睡眠期间可能造成其他CPU空转
spin_unlock(&lock);
实验
这里以 自旋锁 驱动程序进行实验,实验自旋锁死锁问题
在 open()函数中加入了自旋锁加锁, 在 close()函数中加入了自旋锁解锁, 由于在 write()函数中存在 sleep()睡眠函数, 所以会造成内核阻塞,睡眠期间如果使用另一个进程获取该自旋锁, 就会造成死锁
驱动-原子操作实验
实验源码 spinlock.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/delay.h>
#include <linux/atomic.h>
#include <linux/errno.h>
static spinlock_t spinlock_test;//定义spinlock_t类型自旋变量
static int flag=1;
static int open_test(struct inode *inode,struct file *file)
{
spin_lock(&spinlock_test); //自旋枷锁
if(flag!=1){
//判断标志位flag 的值是否等于1
spin_unlock(&spinlock_test)<

最低0.47元/天 解锁文章
904

被折叠的 条评论
为什么被折叠?



