在多线程应用中,程序员会使用互斥锁(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 函数上会花费较长时间)

  1. 把UpdateSharedData2 函数访问的数据结构分为两部分,各使用一把互斥锁。然后把UpdateSharedData2 函数分解为两个函数。通过分离关键代码的方式来减少锁争用。
  2. 分析UpdateSharedData2 函数,如果UpdateSharedData2 函数并不需要对整个执行过程进行保护,那你可以考虑在函数中需要访问共享数据的点插入关键代码段,而不是封闭整个函数调用。

根据获取和释放锁的开销来调整关键代码段的大小。我们可做的事有:

  1. 整合小关键代码段,以分担锁定开销。
  2. 将锁争用现象严重的大型关键代码段划分为较小的关键代码段。
  3. 将锁关联至特定的共享数据,借以最大限度减少锁争用问题。 最佳解决方案可能处于为每个共享数据元素创建一个锁和为所有共享数据创建一个锁两种极端之间。

采用大关键代码段意味着算法本身的并发性非常低,或者线程间的数据划分并不理想。 对于前者,只能更改算法。 对于后者,可尝试为共享数据创建本地拷贝,支持线程异步访问。

如果我们考虑上下文切换的开销,那么我们应该决定使用互斥锁还是自旋锁。自旋锁是一个等待循环,会一直占用CPU,因此没有上下文切换。对于正等待进入小关键代码段的线程来说,使用自旋锁可能比互斥锁有更高的性能。但是,鉴于处于等待状态的线程在旋转等待循环中仍将占用 CPU 资源, 只有当线程在关键代码段中所花费的时间极短,不良影响低于环境切换时,才推荐使用旋转等待循环。

在支持英特尔® 超线程技术(英特尔® HT 技术)的处理器中,会在同一 CPU 核心上创建两路逻辑处理器。 旋转线程和正执行有用任务的线程务必会争夺逻辑处理器资源。与对称多处理器系统相比,旋转线程对采用英特尔超线程技术的系统中多线程应用性能的影响更大。 在这种情况下,应将自旋锁的自旋计数调低,或者不采用自旋锁。

Linux -- 管理锁争用(翻译)的更多相关文章

  1. [转]了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密_Mr_Indigo的空间

    了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密 关系型数据库,如SQL Server,使用锁来避免多用户修改数据时的并发冲突.当一组数据被某个用户锁定时,除非第一个用户结束修 ...

  2. 了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密

    关系型数据库,如SQL Server,使用锁来避免多用户修改数据时的并发冲突.当一组数据被某个用户锁定时,除非第一个用户结束修改并释放锁,否则其他用户就无法修改该组数据. 有些数据库,包括SQL Se ...

  3. 在Linux下锁住键盘和鼠标而不锁屏

    假如在你正看着屏幕上的某些重要的事情时,你不想让你的小猫或者小狗在你的键盘上行走,或者让你的孩子在键盘上瞎搞一气,那我建议你试试 xtrlock 这个工具. 假如在你正看着屏幕上的某些重要的事情时,你 ...

  4. 调整Kali Linux的锁屏时间

    调整Kali Linux的锁屏时间   锁屏是保护隐私的一种重要机制.当用户不操作电脑一段时间后,系统会进入锁屏状态.用户需要输入口令,才能重新进入系统.避免因为操作人员离开电脑后,被其他人员利用现有 ...

  5. Kali Linux 网络扫描秘籍 翻译完成!

    Kali Linux 网络扫描秘籍 翻译完成! 原书:Kali Linux Network Scanning Cookbook 译者:飞龙 在线阅读 PDF格式 EPUB格式 MOBI格式 代码仓库 ...

  6. linux管理面板

    小编在这儿给大家介绍几款linux管理面板,希望感兴趣的童鞋可以去尝试下.个人觉得宝塔和appnode这两个面板不仅从功能和样式都还是做的比较好的,但是部分功能是收费的,但是webmin绝对是一款免费 ...

  7. linux 管理权限

    linux 管理权限 linux 文件 权限 1.使用 ls -l 命令 执行结果如下(/var/log) : drwxr-x--- 2 root adm 4096 2013-08-07 11:03 ...

  8. Linux 管理环境变量的文件分为系统级和用户级别

    Linux 管理环境变量的文件分为系统级和用户级别 管理环境变量的文件也分为系统级和用户级别: 1.系统级:/etc/profile:该文件是用户登录时,操作系统定制用户环境时使用的第一个文件,应用于 ...

  9. mysql 开发进阶篇系列 7 锁问题(innodb锁争用情况及锁模式)

    1 .获取innodb行锁争用情况 1.1 通过检查innodb_row_lock状态变量来分析系统上的行锁的争夺情况 SHOW STATUS LIKE 'innodb_row_lock%' 通过in ...

随机推荐

  1. Linux网络编程综合运用之MiniFtp实现(三)

    前面已经对FTP相关的一些概念有了基本的认识,接下来就要进入代码编写阶段了,也是非常兴奋的阶段,在开启这个它之前先对项目需求进行一个梳理,对其我们要实现的FTP服务器是一个什么样子. ftp命令列表 ...

  2. 链表实现队列(python)

    # -*- coding: utf-8 -*- from collections import deque class Node(object): def __init__(self, value=N ...

  3. logstash可以考虑在项目中用起来

    在用Node.js开发项目的时候,我们常用 log4js 模块来进行日志的记录,可以通过配置 log4js 的 Appenders 将日志输出到Console.File和GELF等不同的地方. log ...

  4. ASP.NET 下配置请求大小、请求时间等参数

    在邮件发送系统或者其他一些传送文件的网站中,用户传送文件的大小是有限制的,因为这样不但可以节省服务器的空间,还可以提高传送文件的速度.下面介绍如何在Web.Config文件中配置限制上传文件大小与时间 ...

  5. dos中查找端口的PID,并在任务管理器中处理端口

    本文来源https://www.cnblogs.com/lsyf/p/8979012.html 1.查看所有端口进程 首先点击开始菜单选择运行,接着在运行对话框中输入“cmd”,回车打开命令提示符窗口 ...

  6. Jenkins 参数化构建(Extended Choice Parameter)

    1.下载安装 Extended Choice Parameter 插件 2.打开job--->General--->参数化构建过程--->Extended Choice Parame ...

  7. 在 windows 上安装 git 2.15

    下载 by win 下载地址:https://git-scm.com/download/win 如下图.选择对应的版本下载: 安装 by win 1.双击下载好的git安装包.弹出提示框.如下图: 2 ...

  8. 使用jQuery快速高效制作网页交互特效---JavaScript对象及初始面向对象

    一.JavaScript中的基本数据类型 number(数值类型)    string(字符串类型)    boolean(布尔类型)    null(空类型)    undefined(未定义类型) ...

  9. Linux swap的创建与配置

    在Linux下,swap的作用类似Windows系统下的“虚拟内存”.当物理内存不足时,拿出部分硬盘空间当SWAP分区(虚拟成内存)使用,从而解决内存容量不足的情况.Linux下的swap有两种实现形 ...

  10. divisors 数学

    divisors 数学 给定\(m\)个不同的正整数\(a_1, a_2,\cdots, a_m\),请对\(0\)到\(m\)每一个\(k\)计算,在区间\([1, n]\)里有多少正整数是\(a\ ...