Linux -- 管理锁争用(翻译)
在多线程应用中,程序员会使用互斥锁(mutex)来同步线程进入可访问共享资源的代码区域的行为。受这些锁保护的代码区域被称为关键代码段(Critical Section)。如果关键代码段中已存在一个线程,那么其他任何线程都不可进入该代码段。
线程应该尽量缩短在关键代码段花费的时间,进而减少其他线程在代码段外闲置等待获得锁的时间。但是又不能盲目地划分出很多的小代码段。
例1
Begin Thread Function ()
Initialize ()
BEGIN CRITICAL SECTION 1
UpdateSharedData1 ()
END CRITICAL SECTION 1
DoFunc1 ()
BEGIN CRITICAL SECTION 2
UpdateSharedData2 ()
END CRITICAL SECTION 2
DoFunc2 ()
End Thread Function ()
上例中,关键代码段被DoFunc1 ()函数分离开来。
如果线程在DoFunc1 ()中花费的时间很长,这样做是值得的。
但是如果线程在DoFunc1 ()中花费的时间很短,那更好的方案是将两个小关键代码段合并为一个关键代码段
例2
Begin Thread Function ()
Initialize ()
BEGIN CRITICAL SECTION 1
UpdateSharedData1 ()
DoFunc1 ()
UpdateSharedData2 ()
END CRITICAL SECTION 1
DoFunc2 ()
End Thread Function ()
例1中,关键代码段被DoFunc1 ()函数分离开来。UpdateSharedData1 ()和UpdateSharedData2 ()分别由两个锁来同步。例2中,将两个小关键代码段合并为一个大的关键代码段,其中包含了与同步无关的函数DoFunc1 ()。
那么哪种选择更好呢?
这要看情况决定。
如果线程在DoFunc1 ()中花费的时间很长,例1的性能更好。因为例2里,线程获得了锁,却在关键代码中浪费了大量的时间到与同步无关的函数上。
如果线程在DoFunc1 ()中花费的时间很短,例2的性能更好。例1为了在关键代码段中减少DoFunc1 ()的时间,承受了同步两个关键代码段的锁争用开销。如果DoFunc1 ()的时间少于1个锁争用开销,那么例1反而损失了性能。
如果线程在UpdateSharedData2 函数上会花费较长时间,例1的性能更好。因为这种情况下,线程无可避免地将在关键代码段中花费很长的时间。例2中,当线程进入UpdateSharedData2函数时,所有其他线程都堵塞着等待进入UpdateSharedData1函数。因此,我们可以采用例1 ,让其他线程先处理完UpdateSharedData1函数。
尽量把锁关联到特定共享数据。你不应该为共享数据的结构中的每个元素创建一个独立的锁,也不应该创建单个锁来保护到整个结构的访问。最佳的锁粒度应该在这两者之间,需要你把握。
针对上面的最后一个情况(如果线程在UpdateSharedData2 函数上会花费较长时间)
- 把UpdateSharedData2 函数访问的数据结构分为两部分,各使用一把互斥锁。然后把UpdateSharedData2 函数分解为两个函数。通过分离关键代码的方式来减少锁争用。
- 分析UpdateSharedData2 函数,如果UpdateSharedData2 函数并不需要对整个执行过程进行保护,那你可以考虑在函数中需要访问共享数据的点插入关键代码段,而不是封闭整个函数调用。
根据获取和释放锁的开销来调整关键代码段的大小。我们可做的事有:
- 整合小关键代码段,以分担锁定开销。
- 将锁争用现象严重的大型关键代码段划分为较小的关键代码段。
- 将锁关联至特定的共享数据,借以最大限度减少锁争用问题。 最佳解决方案可能处于为每个共享数据元素创建一个锁和为所有共享数据创建一个锁两种极端之间。
采用大关键代码段意味着算法本身的并发性非常低,或者线程间的数据划分并不理想。 对于前者,只能更改算法。 对于后者,可尝试为共享数据创建本地拷贝,支持线程异步访问。
如果我们考虑上下文切换的开销,那么我们应该决定使用互斥锁还是自旋锁。自旋锁是一个等待循环,会一直占用CPU,因此没有上下文切换。对于正等待进入小关键代码段的线程来说,使用自旋锁可能比互斥锁有更高的性能。但是,鉴于处于等待状态的线程在旋转等待循环中仍将占用 CPU 资源, 只有当线程在关键代码段中所花费的时间极短,不良影响低于环境切换时,才推荐使用旋转等待循环。
在支持英特尔® 超线程技术(英特尔® HT 技术)的处理器中,会在同一 CPU 核心上创建两路逻辑处理器。 旋转线程和正执行有用任务的线程务必会争夺逻辑处理器资源。与对称多处理器系统相比,旋转线程对采用英特尔超线程技术的系统中多线程应用性能的影响更大。 在这种情况下,应将自旋锁的自旋计数调低,或者不采用自旋锁。
Linux -- 管理锁争用(翻译)的更多相关文章
- [转]了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密_Mr_Indigo的空间
了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密 关系型数据库,如SQL Server,使用锁来避免多用户修改数据时的并发冲突.当一组数据被某个用户锁定时,除非第一个用户结束修 ...
- 了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密
关系型数据库,如SQL Server,使用锁来避免多用户修改数据时的并发冲突.当一组数据被某个用户锁定时,除非第一个用户结束修改并释放锁,否则其他用户就无法修改该组数据. 有些数据库,包括SQL Se ...
- 在Linux下锁住键盘和鼠标而不锁屏
假如在你正看着屏幕上的某些重要的事情时,你不想让你的小猫或者小狗在你的键盘上行走,或者让你的孩子在键盘上瞎搞一气,那我建议你试试 xtrlock 这个工具. 假如在你正看着屏幕上的某些重要的事情时,你 ...
- 调整Kali Linux的锁屏时间
调整Kali Linux的锁屏时间 锁屏是保护隐私的一种重要机制.当用户不操作电脑一段时间后,系统会进入锁屏状态.用户需要输入口令,才能重新进入系统.避免因为操作人员离开电脑后,被其他人员利用现有 ...
- Kali Linux 网络扫描秘籍 翻译完成!
Kali Linux 网络扫描秘籍 翻译完成! 原书:Kali Linux Network Scanning Cookbook 译者:飞龙 在线阅读 PDF格式 EPUB格式 MOBI格式 代码仓库 ...
- linux管理面板
小编在这儿给大家介绍几款linux管理面板,希望感兴趣的童鞋可以去尝试下.个人觉得宝塔和appnode这两个面板不仅从功能和样式都还是做的比较好的,但是部分功能是收费的,但是webmin绝对是一款免费 ...
- linux 管理权限
linux 管理权限 linux 文件 权限 1.使用 ls -l 命令 执行结果如下(/var/log) : drwxr-x--- 2 root adm 4096 2013-08-07 11:03 ...
- Linux 管理环境变量的文件分为系统级和用户级别
Linux 管理环境变量的文件分为系统级和用户级别 管理环境变量的文件也分为系统级和用户级别: 1.系统级:/etc/profile:该文件是用户登录时,操作系统定制用户环境时使用的第一个文件,应用于 ...
- mysql 开发进阶篇系列 7 锁问题(innodb锁争用情况及锁模式)
1 .获取innodb行锁争用情况 1.1 通过检查innodb_row_lock状态变量来分析系统上的行锁的争夺情况 SHOW STATUS LIKE 'innodb_row_lock%' 通过in ...
随机推荐
- IDEA实用教程(五)——配置IDEA的JVM内存值
---恢复内容开始--- 四. 配置IDEA的JVM内存值 IDEA默认配置的JVM内存值比较低,如果硬件配置较高,可以修改该设置. 该设置需要在工程界面进行. 该操作仅建议内存8G以上,64位操作系 ...
- Run Code Once on First Load (Concurrency Safe)
原文: https://golangcode.com/run-code-once-with-sync/ ------------------------------------------------ ...
- eclipse中JDK环境的搭建
现在就可以用记事本开发java程序了,但是eclipse是一款java开发不可缺少的IDE,并且安装简单,下面说一下步骤,首先下载eclipse, 官网下载链接:http://www.eclipse. ...
- Nginx入门(三)——正向代理
server { resolver 114.114.114.114; #指定DNS服务器IP地址 listen 443; location / { proxy_pass https://$host$r ...
- php类的定义与实例化方法
php类的定义 类是对某个对象的定义.它包含有关对象动作方式的信息,包括它的名称.方法.属性和事件.实际上它本身并不是对象,因为它不存在于内存中.当引用类的代码运行时,类的一个新的实例,即对象,就在内 ...
- 小白学习.NET的初期经验
对于.NET,刚开始确实很迷茫,确实,对于程序员这种职业我不是很了解,我以前是学数控的 ,对于我心目中的程序而言,程序就是我常用的那些代码,毕竟做了四五年的数控,同样都是程序,给我的了解就是都是代码: ...
- fatal: 'origin' does not appear to be a git repository
git push时报以下错误: fatal: 'origin' does not appear to be a git repository fatal: Could not read from re ...
- Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)
答:赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个. 浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改 ...
- Java学习日记基础篇(七) —— 数组、排序
数组 为什么要有数组? 案例:一个养鸡场有六只鸡,他们的体重分别为3kg,5kg,1kg,3.4kg,2kg,50kg.请问这六只鸡的总体重和平均体重是多少? public class test5 { ...
- getLocation需要在app.json中声明permission字段,解决办法
具体开发方法如下: 在 app.json 里面增加 permission 属性配置(小游戏需在game.json中配置): "permission": { "scope. ...