1.故障分析 | 从 Insert 并发死锁分析 Insert 加锁源码逻辑
2.偷偷跟我学这个看源码的广东小技巧,早日解放双手
3.多线程死锁检测的死锁死锁示例分析与实现(linux c)-有向图的应用
4.代码是什么意思?
5.Linux:带你理解死锁(银行家算法详解)及死锁产生的必要条件
6.慎用,Mybatis-Plus这个方法可能导致死锁
故障分析 | 从 Insert 并发死锁分析 Insert 加锁源码逻辑
死锁是数据库并发操作中的常见问题,涉及业务关联、源码机制复杂、代码类型多样等特点,广东给分析带来了挑战。死锁死锁示例oceanbase开源源码本文以MySQL数据库中并发Insert导致死锁为例,源码通过问题发现、代码重现、广东根因分析和解决策略,死锁死锁示例提供一套科学有效的源码死锁处理方案。文章首先概述了死锁的代码基本现象和常见特性,指出死锁触发原因与应用逻辑相关,广东且涉及多个事务。死锁死锁示例由于不同数据库的源码锁实现机制差异,分析死锁问题往往不易。接着,文章详细描述了死锁问题的实例,包括日志提示、innodb status输出和事务执行过程。通过与研发团队的沟通和问题复现,文章进一步分析了事务之间的锁等待和持有状态,提出了问题的具体原因。为解决死锁问题,文章提出了优化唯一索引和调整并发策略的建议,并结合MySQL的锁实现机制,通过源码分析揭示了死锁产生的根本原因。最终,文章总结了避免死锁的关键措施,包括选择适合的隔离级别、减少对Unique索引的依赖,并通过性能数据追踪和源码理解来有效诊断和解决死锁问题。文章旨在为数据库运维人员提供一套实用的死锁处理方法,促进数据库系统稳定性和性能优化。
偷偷跟我学这个看源码的小技巧,早日解放双手
大家好!
在看源码的过程中,查看 Git 提交记录是了解文件演变过程的有效途径。对于如何在 IDEA 中查看这些记录,可能有些同学感到困惑。这篇文章将分享一些实用的小技巧,帮助大家更直观地进行源码学习。
首先,确保你的本地环境配置了 Git。如果还没有安装 Git,强烈建议你先完成安装并熟悉基本操作。
接下来,使用 Git 克隆一个感兴趣的开源项目,例如 Redssion。在 IDEA 中导入项目并查看文件右键菜单,确认是否能找到“Git”选项。如果找不到,可能是 Git 配置问题,进入 IDEA 设置中进行相应的调整。
在 IDEA 的“Version Control”标签页中,你可以看到项目的提交历史。通过这个界面,你可以快速浏览文件的变更情况,了解代码的演变过程。
在日常工作中或撰写文章时,使用 IDEA 的 Git 功能主要关注提交记录,而不是直接在 IDEA 中进行代码提交。这种方式提供了可视化的代码历史,有助于理解代码的变更轨迹。
以 Redssion 为例,通过在 GitHub 的 issues 页面搜索关键词(如“死锁”),可以找到相关的问题讨论和代码修复。关注这些信息能帮助你更快定位问题和学习关键代码变更。
使用 IDEA 的 Git 插件,可以方便地查看特定日期的提交记录。在“Version Control”标签页中,通过过滤功能找到目标日期的提交,这样可以快速定位到关键变更。
通过查看提交记录,你可以了解代码的map集合源码分析具体修改内容,这对于深入理解代码实现和调试问题非常有帮助。例如,在 Redssion 中,可以追踪到特定类的修改历史,了解其功能演进。
此外,通过查看项目的首次提交记录,可以了解项目的起源和发展历程。例如,Dubbo 的首次提交记录反映了项目早期的状态和开发团队的辛勤工作。这些历史记录不仅展示了技术演变,也蕴含了项目发展的故事。
总的来说,利用 IDEA 的 Git 功能探索代码历史,不仅可以帮助你更高效地学习和理解源码,还能深入了解项目的开发背景和演进过程。通过这种方式,源码阅读将变得更具趣味性和实用性。
多线程死锁检测的分析与实现(linux c)-有向图的应用
在多线程编程中,死锁问题是个棘手难题。它源于资源争夺和进程推进顺序的不当,导致进程陷入僵局。当我们需要检测一个程序是否遭遇死锁,首先理解死锁的四个必要条件——互斥、请求保持、不剥夺和环路等待。死锁表现为线程间的资源循环等待,形成有向环形图结构。
死锁问题的根源在于资源竞争和进程顺序,例如,两个线程A和B分别按顺序争夺资源a和b,形成一个循环,进而影响其他线程。要解决这个问题,关键在于理解有向环的检测。当程序中出现死锁,就反映了线程间的锁关系形成了环形链,这可通过维护加锁和释放锁后有向图的状态来识别。
检测死锁的过程涉及三个步骤:在加锁前检查资源占用情况,加锁后建立线程和锁的对应关系,并在释放锁后更新图状态。利用Hook技术,我们可以自定义加锁和解锁函数,集成环形链检测逻辑,让开发者在常规操作中无需额外关注死锁问题。
在源代码实现中,会用到图的基本结构,如结点包含线程ID和锁ID,邻接表表示边,以及深度优先遍历(DFS)来检测环。通过深度遍历,如果遇到已访问过的结点,就说明存在死锁。编译并运行源代码(deadlock.c)如下:
gcc -o deadlock deadlock.c -lpthread -ldl;
总之,死锁问题的检测与解决涉及到对资源竞争、进程顺序和图论的理解,通过构建和维护有向图,可以有效地识别和预防多线程程序中的死锁。
代码是什么意思?
代码 含意
0 0x 作业完成。
1 0x 不正确的函数。
2 0x 系统找不到指定的档案。
3 0x 系统找不到指定的路径。
4 0x 系统无法开启档案。
5 0x 拒绝存取。
6 0x 无效的代码。
7 0x 储存体控制区块已毁。
8 0x 储存体空间不足,无法处理这个指令。
9 0x 储存体控制区块地址无效。
0xA 环境不正确。
0xB 尝试加载一个格式错误的程序。
0xC 存取码错误。
0xD 资料错误。
0xE 储存体空间不够,齐装网 源码无法完成这项作业。
0xF 系统找不到指定的磁盘驱动器。
0x 无法移除目录。
0x 无法移除目录。
0x 系统无法将档案移到 其它的磁盘驱动器。
0x 没有任何档案。
0x 储存媒体为写保护状态。
0x 系统找不到指定的装置。
0x 装置尚未就绪。
0x 装置无法识别指令。
0x 资料错误 (cyclic redundancy check)
0x 程序发出一个长度错误的指令。
0x 磁盘驱动器在磁盘找不到 持定的扇区或磁道。
0xA 指定的磁盘或磁盘无法存取。
0xB 磁盘驱动器找不到要求的扇区。
0xC 打印机没有纸。
0xD 系统无法将资料写入指定的磁盘驱动器。
0xE 系统无法读取指定的装置。
0xF 连接到系统的某个装置没有作用。
0x The process cannot access the file because it is being
used by another process.
0x 档案的一部份被锁定, 现在无法存取。
0x 磁盘驱动器的磁盘不正确。 请将 %2 (Volume Serial
Number: %3) 插入磁盘机%1。
0x 开启的分享档案数量太多。
0x 到达档案结尾。
0x 磁盘已满。
0x 不支持这种网络要求。
0x 远程计算机无法使用。
0x 网络名称重复。
0x 网络路径找不到。
0x 网络忙碌中。
0x The specified network resource or device is no longer
available.
0x The network BIOS command limit has been reached.
0x 网络配接卡发生问题。
0xA 指定的服务器无法执行要求的作业。
0xB 网络发生意外错误。
0xC 远程配接卡不兼容。
0xD 打印机队列已满。
0xE 服务器的空间无法储存等候打印的档案。
0xF 等候打印的档案已经删除。
0x 指定的网络名称无法使用。
0x 拒绝存取网络。
0x 拒绝存取网络。
0x 网络资源类型错误。
0x 网络名称找不到。
0x 超过区域计算机网络配接卡的名称限制。
0x 超过网络 BIOS 作业阶段的限制。
0x 远程服务器已经暂停或者正在起始中。
0x 由于联机数目已达上限,此时无法再联机到这台远程计算机。
0x 指定的打印机或磁盘装置已经暂停作用。
0x 档案已经存在。
0x 无法建立目录或档案。
0x INT 0x 处理这项要求的储存体无法使用。
0x 近端装置名称已经在使用中。
0x 指定的网络密码错误。
0x 参数错误。
0x 网络发生资料写入错误。
0x 此时系统无法执行其它行程。
0x 无法建立其它的系统 semaphore。
0x 属于其它行程专用的 semaphore.
0x semaphore 已经设定,而且无法关闭。
0x 无法指定 semaphore 。
0x 在岔断时间无法要求专用的 semaphore 。
0x 在岔断时间无法要求专用的 semaphore 。
0x 此 semaphore 先前的拥有权已经结束。
0xA 请将磁盘插入 %1。
0xB 因为代用的磁盘尚未插入,所以程序已经停止。
0xC 磁盘正在使用中或被锁定。
0xD Pipe 已经中止。
0xE 系统无法开启指定的 装置或档案。
0xF 档名太长。
0x 磁盘空间不足。
0x 没有可用的内部档案标识符。
0x 目标内部档案标识符不正确。
0x 由应用程序所执行的微 拍卖系统源码 IOCTL 呼叫 不正确。
0x 写入验证参数值不正确。
0x 系统不支持所要求的指令。
0x 此项功能仅在 Win 模式有效
0x semaphore 超过逾时期间。
0xA 传到系统呼叫的资料区域 太小。
0xB 文件名、目录名称或储存体卷标语法错误。
0xC 系统呼叫层次不正确。
0xD 磁盘没有设定卷标。
0xE 找不到指定的模块。
0xF 找不到指定的程序。
0x 没有子行程可供等待。
0x 没有子行程可供等待。
0x %1 这个应用程序无法在 Win 模式下执行。
0x Attempt to use a file handle to an open disk
partition for an operation other than raw disk I/O.
0x 尝试将档案指针移至档案开头之前。
0x 无法在指定的装置或档案,设定档案指针。
0x JOIN 或 SUBST 指令 无法用于 内含事先结合过的磁盘驱动器。
0x 尝试在已经结合的磁盘驱动器,使用 JOIN 或 SUBST 指令。
0x 尝试在已经替换的磁盘驱动器,使 用 JOIN 或 SUBST 指令。
0x 系统尝试删除 未连结过的磁盘驱动器的连结关系。
0xA 系统尝试将磁盘驱动器结合到已经结合过之磁盘驱动器的目录。
0xB 系统尝试将磁盘驱动器替换成已经替换过之磁盘驱动器的目录。
0xC 系统尝试将磁盘驱动器替换成已经替换过之磁盘驱动器的目录。
0x 系统尝试将磁盘驱动器 SUBST 成已结合的磁盘驱动器 目录。
0xE 系统此刻无法执行 JOIN 或 SUBST。
0xF 系统无法将磁盘驱动器结合或替换同一磁盘驱动器下目录。
0x 这个目录不是根目录的子目录。
0x 目录仍有资料。
0x 指定的路径已经被替换过。
0x 资源不足,无法处理这项 指令。
0x 指定的路径这时候无法使用。
0x 指定的路径这时候无法使用。
0x 尝试要结合或替换的磁盘驱动器目录,是已经替换过的的目标。
0x CONFIG.SYS 文件未指定系统追踪信息,或是追踪功能被取消。
0x 指定的 semaphore事件 DosMuxSemWait 数目不正确。
0x DosMuxSemWait 没有执行;设定太多的 semaphore。
0x DosMuxSemWait 清单不正确。
0xA 您所输入的储存媒体标 元长度限制。
0xB 无法建立其它的执行绪。
0xC 接收行程拒绝接受信号。
0xD 区段已经被舍弃,无法被锁定。
0xE 区段已经解除锁定。
0xF 执行绪识别码的地址不正确。
0xA0 传到 DosExecPgm 的自变量字符串不正确。
0xA1 指定的路径不正确。
0xA2 信号等候处理。
0xA4 系统无法建立执行绪。
0xA7 无法锁定档案的部份范围。
0xAA 所要求的资源正在使用中。
0xAD 取消范围的锁定要求不明显。
0xAE 档案系统不支持自动变更锁定类型。
0xB4 系统发现不正确的区段号码。
0xB6 操作系统无法执行 %1。
0xB6 操作系统无法执行 %1。
0xB7 档案已存在,无法建立同一档案。
0xBA 传送的旗号错误。
0xBB 指定的系统旗号找不到。
0xBC 操作系统无法执行 %1。
0xBD 操作系统无法执行 %1。
0xBE 操作系统无法执行 %1
0xBF 无法在 Win 模式下执行 %1。
0xC0 操作系统无法执行 %1。
0xC1 %1 不是正确的 Win 应用程序。
0xC2 操作系统无法执行 %1。
0xC3 操作系统无法执行 %1。
0xC4 操作系统无法执行 这个应用程序。
0xC5 操作系统目前无法执行 这个应用程序。
0xC6 操作系统无法执行 %1。通用音频驱动源码
0xC7 操作系统无法执行 这个应用程序。
0xC8 程序代码的区段不可以大于或等于 KB。
0xC9 操作系统无法执行 %1。
0xCA 操作系统无法执行 %1。
0xCB 系统找不到输入的环境选项。\r
0xCD 在指令子目录下,没有任何行程有信号副处理程序。
0xCE 文件名称或扩展名太长。
0xCF ring 2 堆栈使用中。
0xCF ring 2 堆栈使用中。
0xD0 输入的通用档名字元 * 或 ? 不正确, 或指定太多的通用档名字元。
0xD1 所传送的信号不正确。
0xD2 无法设定信号处理程序。
0xD4 区段被锁定,而且无法重新配置。
0xD6 附加到此程序或动态连结模块的动态连结模块太多。
0xD7 Can’t nest calls to LoadModule.
0xE6 The pipe state is invalid.
0xE7 所有的 pipe instances 都在忙碌中。
0xE8 The pipe is being closed.
0xE9 No process is on the other end of the pipe.
0xEA 有更多可用的资料。
0xF0 作业阶段被取消。
0xFE 指定的延伸属性名称无效。
0xFF 延伸的属性不一致。
0x 没有可用的资料。
0xA 无法使用 Copy API。
0xB 目录名称错误。
0x 延伸属性不适用于缓冲区。
0x 在外挂的档案系统上的延伸属性档案已经毁损。
0x 延伸属性表格文件满。
0x 指定的延伸属性代码无效。
0x 指定的延伸属性代码无效。
0xA 外挂的这个档案系统不支持延伸属性。
0x 意图释放不属于叫用者的 mutex。
0xA semaphore 传送次数过多。
0xB 只完成 Read/WriteProcessMemory 的部份要求。
0xD 系统找不到位于讯息文件 %2 中编号为 0x%1 的讯息。
0xE7 尝试存取无效的地址。
0x 运算结果超过 位。
0x 信道的另一端有一个行程在接送资料。
0x 等候行程来开启信道的另一端。
0xE2 存取延伸的属性被拒。
0xE3 由于执行绪结束或应用程序要求,而异常终止 I/O 作业。
0xE4 重叠的 I/O 事件不是设定成通知状态。
0xE5 正在处理重叠的 I/O 作业。
0xE6 对内存位置的无效存取。
0xE7 执行 inpage 作业发生错误。
0xE9 递归太深,堆栈满溢。
0xEA 窗口无法用来传送讯息。
0xEB 无法完成这项功能。
0xEC 旗号无效。
0xED 储存媒体未含任何可辨识的档案系统。 请确定以加载所需
的系统驱动程序,而且该储存媒体并未毁损。
0xEE 储存该档案的外部媒体发出警告,表示该已开启档案已经无效。
0xEF 所要求的作业无法在全屏幕模式下执行。
0xF0 An attempt was made to reference a token that does
not exist.
0xF1 组态系统登录数据库毁损。
0xF2 组态系统登录机码无效。
0xF3 无法开启组态系统登录机码。
0xF4 无法读取组态系统登录机码。
0xF5 无法写入组态系统登录机码。
0xF6 系统登录数据库中的一个档案必须使用记录或其它备份还
原。 已经还原成功。
0xF7 系统登录毁损。其中某个档案毁损、或者该档案的 系统映
对内存内容毁损、会是档案无法复原。
0xF8 系统登录起始的 I/O 作业发生无法复原的错误。 系统登录
无法读入、写出或更新,其中的一个档案 内含系统登录在内存中的内容。
0xF9 系统尝试将档案加载系统登录或将档案还原到系统登录中,
但是,指定档案的格式不是系统登录文件的格式。
0xFA 尝试在标示为删除的系统登录机码,执行不合法的操作。
0xFA 尝试在标示为删除的系统登录机码,执行不合法的操作。
0xFB 系统无法配置系统登录记录所需的空间。
0xFC 无法在已经有子机码或数值的系统登录机码建立符号连结。
0xFD 无法在临时机码下建立永久的子机码。
0xFE 变更要求的通知完成,但信息 并未透过呼叫者的缓冲区传
回。呼叫者现在需要自行列举档案,找出变更的地方。
0xB 停止控制已经传送给其它服务 所依峙的一个服务。
0xC 要求的控制对此服务无效
0xF8 系统登录起始的 I/O 作业发生无法复原的错误。 系统登录
无法读入、写出或更新,其中的一个档案 内含系统登录在内存中的内容。
0xF9 系统尝试将档案加载系统登录或将档案还原到系统登录中,
但是,指定档案的格式不是系统登录文件的格式。
0xFA 尝试在标示为删除的系统登录机码,执行不合法的操作。
0xFA 尝试在标示为删除的系统登录机码,执行不合法的操作。
0xFB 系统无法配置系统登录记录所需的空间。
0xFC 无法在已经有子机码或数值的系统登录机码建立符号连结。
0xFD 无法在临时机码下建立永久的子机码。
0xFE 变更要求的通知完成,但信息 并未透过呼叫者的缓冲区传
回。呼叫者现在需要自行列举档案,找出变更的地方。
0xB 停止控制已经传送给其它服务 所依峙的一个服务。
0xC 要求的控制对此服务无效
0xC 要求的控制对此服务无效
0xD The service did not respond to the start or control
request in a timely fashion. 0xE 无法建立服务的执行绪。
0xF 服务数据库被锁定。
0x 这种服务已经在执行。
0x 帐户名称错误或者不存在。
0x 指定的服务暂停作用,无法激活。
0x 指定循环服务从属关系。
0x 指定的服务不是安装进来的服务。
0x 该服务项目此时无法接收控制讯息。
0x 服务尚未激活。
0x 无法联机到服务控制程序。
0x 处理控制要求时,发生意外状况。
0x 指定的数据库不存在。
0xA 服务传回专属于服务的错误码。
0xB The process terminated unexpectedly.
0xC 从属服务或群组无法激活。
0xD 因为登入失败,所以没有激活服务。
0xE 在激活之后,服务在激活状态时当机。
0xF 指定服务数据库锁定无效。
0x 指定的服务已经标示为删除。
0x 指定的服务已经存在。
0x 系统目前正以上一次执行成功的组态执行。
0x 从属服务不存在,或已经标示为删除。
0x 目前的激活已经接受上一次执行成功的 控制设定。
0x 上一次激活之后,就没有再激活服务。
0x 指定的名称已经用于服务名称或服务显示 名称。
0xC 已经到了磁带的最后。
0xD 到了档案标示。
0xE 遇到磁带的开头或分割区。
0xC 已经到了磁带的最后。
0xD 到了档案标示。
0xE 遇到磁带的开头或分割区。
0xF 到了档案组的结尾。
0x 磁带没有任何资料。
0x 磁带无法制作分割区。
0x 存取多重容体的新磁带时,发现目前 区块大小错误。
0x 加载磁带时,找不到磁带分割区信息。
0x 无法锁住储存媒体退带功能。
0x 无法锁住储存媒体退带功能。
0x 无法解除加载储存媒体。
0x 磁盘驱动器中的储存媒体已经变更。
0x 已经重设 I/O 总线。
0x 磁盘驱动器没有任何储存媒体。
0x 目标 multi-byte code page,没有对应 Unicode 字符。
0xA 动态链接库 (DLL) 起始例程失败。
0xB 系统正在关机。
0xC 无法中止系统关机,因为没有关机的动作在进行中。
0xD 因为 I/O 装置发生错误,所以无法执行要求。
0xE 序列装置起始失败,会取消加载序列驱动程序。
0xF 无法开启装置。这个装置与其它装置共享岔断要求 (IRQ)。
至少已经有一个使用同一IRQ 的其它装置已经开启。
0x A serial I/O operation was completed by another
write to the serial port. (The IOCTL_SERIAL_XOFF_COUNTER reached zero.)
0x 因为已经过了逾时时间,所以序列 I/O 作业完成。
(IOCTL_SERIAL_XOFF_COUNTER 不是零。)
0x 在磁盘找不到任何的 ID 地址标示。
0x 磁盘扇区 ID 字段与磁盘控制卡追踪地址 不符。
0x 软式磁盘驱动器控制卡回报了一个软式磁盘驱动器驱动程序无法识别的错误。
0x 软式磁盘驱动器控制卡传回与缓存器中不一致的结果。
0x 存取硬盘失败,重试后也无法作业。
0x 存取硬盘失败,重试后也无法作业。
0x 存取硬盘时,必须重设磁盘控制卡,但是 连重设的动作也失败。
0x 到了磁带的最后。
0xA 可用服务器储存空间不足,无法处理这项指令。
0xB 发现潜在的死锁条件。
0xC 指定的基本地址或档案位移没有适当 对齐。
0x 尝试变更系统电源状态,但其它的应用程序或驱动程序拒绝。
0x 系统 BIOS 无法变更系统电源状态。
0xE 指定的程序需要新的 Windows 版本。
0xF 指定的程序不是 Windows 或 MS-DOS 程序。
0x 指定的程序已经激活,无法再激活一次。
0x 指定的程序是为旧版的 Windows 所写的。
0x 执行此应用程序所需的链接库档案之一毁损。
0x 没有应用程序与此项作业的指定档案建立关联。
0x 传送指令到应用程序发生错误。
0x 找不到执行此应用程序所需的链接库档案。
0xB0 指定的装置名称无效。
0xB1 装置现在虽然未联机,但是它是一个记忆联机。
0xB2 尝试记忆已经记住的装置。
0xB3 提供的网络路径找不到任何网络提供程序。
0xB3 提供的网络路径找不到任何网络提供程序。
0xB4 指定的网络提供程序名称错误。
0xB5 无法开启网络联机设定文件。
0xB6 网络联机设定文件坏掉。
0xB7 无法列举非容器。
0xB8 发生延伸的错误。
0xB9 指定的群组名称错误。
0xBA 指定的计算机名称错误。
0xBB 指定的事件名称错误。
0xBC 指定的网络名称错误。
0xBD 指定的服务名称错误。
0xBE 指定的网络名称错误。
0xBF 指定的资源共享名称错误。
0xC0 指定的密码错误。
0xC1 指定的讯息名称错误。
0xC2 指定的讯息目的地错误。
0xC3 所提供的条件与现有的条件组发生冲突。
0xC4 尝试与网络服务器联机,但是 与该服务器的联机已经太多。
0xC5 其它网络计算机已经在使用这个工作群组或网域名称。
Linux:带你理解死锁(银行家算法详解)及死锁产生的必要条件
理解Linux中的死锁问题,特别是通过银行家算法来解决。死锁是一种程序执行过程中,多个线程因资源竞争而陷入无法继续的状态。死锁产生的关键条件包括互斥、请求与保持、不可抢占和循环等待。要预防死锁,可以尝试破坏这些条件,如采用"按序分配"策略,避免形成循环等待,以及在资源分配时考虑系统的安全状态。
银行家算法的核心是,进程在运行前声明所需的资源数量,系统根据资源总量和进程声明进行分配。在分配过程中,系统会检查分配后的状态是否会导致安全问题,如死锁。若发现可能的死锁,算法会通过回溯资源分配或非阻塞加锁来解除死锁。在高性能应用中,无锁编程(如CAS锁、原子操作)是常用策略以提高程序性能。
举例来说,如果有五个线程和三种资源,死锁检测与银行家算法主要关注资源分配的顺序和安全状态。正确理解这些概念,可以帮助避免死锁,确保资源的有效使用。学习资料和内核技术交流群可以在获取,内核源码技术学习路线和视频教程等资源也一应俱全。
慎用,Mybatis-Plus这个方法可能导致死锁
A同学在生产环境使用了Mybatis-Plus提供的 com.baomidou.mybatisplus.extension.service.IService#saveOrUpdate(T, com.baomidou.mybatisplus.core.conditions.Wrapper) 方法(以下简称B方法),并发场景下,数据库报了如下错误
死锁现象的原因分析
理论与实际操作相结合,确定死锁是由间隙锁导致的。
死锁定义为两个事务互相等待对方持有的锁,导致互相阻塞,从而导致死锁。间隙锁则是MySQL为避免幻读,向左找第一个比当前索引值小的值,向右找第一个比当前索引值大的值(没有则为正无穷),将此区间锁住,阻止其他事务在此区间插入数据。
MySQL引入间隙锁是为了与Record lock组合成Next-key lock,以便在可重复读这种隔离级别下避免幻读。
在并发场景下,事务一和事务二可能在对方持有的间隙锁上互相等待,导致死锁。
通过源码分析,发现B方法的逻辑不按照常规流程进行,先执行修改操作,而不是先查询。这可能导致在修改时增加了间隙锁,从而在并发场景下导致死锁。
通过验证间隙锁死锁的场景,可以清楚地看到锁类型是行锁,锁模式是间隙锁。
分析表明间隙锁加锁是非互斥的,即事务一对间隙A加锁后,事务二依然可以给间隙A加锁。
解决死锁的方法
推荐自定义saveOrUpdate方法,而非简单地关闭间隙锁。关闭间隙锁的方法仅适用于当前业务场景确实不关心幻读的问题。自定义方法可以避免Mybatis-Plus提供的方法中的额外反射操作和事务处理,减少额外开销。
拓展分析
如果两个事务修改的是存在的行,MySQL会使用Record Lock而非间隙锁,这与间隙锁不同,Record Lock是互斥的,即不同的事务不能同时对同一行记录添加Record Lock。
结论
虽然Mybatis-Plus提供的方法可能引起死锁,但它仍是一款优秀的增强框架,提供了高效的lambda写法,提高开发效率。在使用时,应秉持辩证态度,熟悉的方法大胆尝试,陌生的方法谨慎使用。
linux 内核 spinlock 的实现
在Linux内核中,共享对象的互斥处理常常面临复杂性问题,源于其内部并发机制的复杂性。这可能包括单核多进程(线程)间的伪并发,或是SMP架构下的真实并发。同时,还需考虑中断和下半部机制对并发的影响,使并发编程变得更为复杂。
共享数据加锁是并发编程中基本的共识。Linux内核提供了多种锁机制,以适应不同的并发情况。没有哪一种锁能适应所有场景,即使有,其适用性也会受到兼容性与针对性之间的权衡。
在所有锁机制中,spin lock和mutex lock应用最为广泛。mutex lock在请求资源时若资源不可用,则进程会进入睡眠状态,直到资源重新开放。这种方式节省了CPU资源,适用于某些特定情况。然而,在某些场景下,mutex lock并不适用。一方面,从微观角度来看,虽然进程切换的开销通常很小,但如果确定进入临界区的时间小于进程切换的时间,且硬件发展使更多开销隐含在进程切换中,使用mutex lock的开销可能不再合理。另一方面,中断上下文中不能使用mutex lock,因此需要使用spinlock来实现共享对象的互斥访问。
spinlock的核心思想是“旋转”,当进程无法获得spinlock保护的临界区访问权时,它会原地等待资源,同时不断地尝试查询是否能获得锁。spinlock的实现主要包括初始化、加锁和解锁三个过程,通过简单的编程接口完成。
spinlock接口包括但不限于spin_lock_irq、spin_unlock_irq、spin_lock_irqsave、spin_unlock_irqstore、spin_lock_bh、spin_unlock_bh等。这些接口允许在不同场景下灵活地使用spinlock,例如在中断上下文禁止中断、保存中断状态或在下半部中禁止下半部等。
在分析spinlock之前,需要理解在使用过程中可能会遇到的并发情况。内核抢占、中断抢占、SMP架构下的并发执行以及下半部的抢占都是需要考虑的因素。对于自旋锁,内核抢占和中断都是明显的风险点,通常需要在使用自旋锁前禁止这些情况。中断服务程序和普通进程之间竞争同一锁时,需要在中断服务程序中禁止中断,而普通进程在使用spinlock时则不需要。在SMP架构下,需要考虑加解锁操作的原子性和独占性。
一个完善的spinlock实现应该具备以下特点:在申请锁时关闭内核抢占,释放锁时开启内核抢占;如果出现中断或进程间的spinlock竞争,进程中的锁操作需要关闭中断;在中断下半部或进程中出现spinlock竞争时,需要关闭中断下半部;在多核系统下,加解锁的操作函数需要具备原子性或独占性。
spinlock的源码实现通常涉及到单核与多核架构的区分,以及内核支持的死锁检测和调试功能。在arm SMP平台上,spinlock实现包含多层宏定义,以适应不同的需求。spinlock结构体spinlock_t负责管理加解锁操作,通过owner和next变量完成。初始化、加锁和释放锁的过程涉及到一系列的函数调用和宏定义,实现复杂的逻辑。
spinlock在单核和多核系统中的实现方式有所不同,单核系统可以通过简单的变量来管理锁状态,而多核系统则需要更复杂的机制来处理并发和独占性问题。通过使用嵌入汇编程序,spinlock实现能够确保加解锁操作的原子性,从而防止并发执行中可能出现的问题。
spinlock的使用涉及到多个并发情况的考虑,包括内核抢占、中断抢占、多核并发执行以及下半部的抢占。在设计和实现spinlock时,需要平衡兼容性与针对性,确保在不同场景下都能有效地实现资源的互斥访问。深入理解spinlock的实现原理和具体细节,对于优化并发代码的性能和避免死锁至关重要。
请记住内核中这个勤劳的监测卫士---Watchdog(Soft lockup篇)
在内核安全和稳定性问题的探索中,我们需要深入了解其中的关键组件,如监视器卫士-Watchdog。它的功能在于监控系统运行状态,确保系统的稳定性和安全性。一旦系统出现异常死锁、挂起或死机等问题,Watchdog的作用就显得尤为重要。当系统出现这些异常情况,Watchdog会自动重启系统并收集程序崩溃时的运行数据,即crash dump,为后续的故障排查提供宝贵的线索。
Watchdog的运作原理基于两种不同的锁状态:soft lockup和hard lockup。在驱动中加入特定代码,如使用spinlock()实现关抢占,可触发soft lockup,此时系统中的[watchdog/x]线程无法被调度。中断处理函数kernel/watchdog.c/watchdog_timer_fn()会在特定条件下唤醒喂狗线程。通过分析流程图和源代码,我们可以深入了解Watchdog的工作机制,例如,如何注册线程、更新变量、绑定中断处理函数等。
深入分析soft lockup问题时,我们需关注系统中进程或线程持续执行时间过长的情况,这可能导致其他进程无法调度,形成软锁死。通过细致分析相关日志和代码,我们可以定位问题原因并采取相应解决策略。
对于内核配置,了解Watchdog的配置结论,如如何激活或调整其频率,对于维护系统稳定性和安全性至关重要。此外,理解Watchdog在内核进程调度、锁机制和死锁处理等方面的关联,有助于我们深入掌握内核的核心要点。
总结而言,Watchdog是内核中一个重要的安全组件,通过监控系统运行状态,有效防止了死锁、挂起和死机等问题的发生。了解其工作原理和配置方法,对于提升系统稳定性和安全性具有重要意义。在后续的文章中,我们将深入探讨hard lockup问题的解决策略,帮助读者在遇到这类问题时能够从容应对。