C++ 各类mutex和读写锁性能比较

这篇具有很好参考价值的文章主要介绍了C++ 各类mutex和读写锁性能比较。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

mutex和rwmutex类型基本概念

pthread_mutex_t:互斥锁,同一瞬间只能有一个线程能够获取锁,其他线程在等待获取锁的时候会进入休眠状态。因此pthread_mutex_t消耗的CPU资源很小,但是性能不高,因为会引起线程切换。

pthread_spinlock_t:自旋锁,同一瞬间也只能有一个线程能够获取锁,不同的是,其他线程在等待获取锁的过程中并不进入睡眠状态,而是在 CPU上进入“自旋”等待。自旋锁的性能很高,但是只适合对很小的代码段加锁(或短期持有的锁),自旋锁对CPU的占用相对较高。

pthread_rwlock_t:读写锁,同时可以有多个线程获得读锁,同时只允许有一个线程获得写锁。其他线程在等待锁的时候同样会进入睡眠。读写锁在互斥锁的基础上,允许多个线程“读”,通常在读多写少的场景下能提高性能。

std::mutex:互斥锁,同一瞬间只能有一个线程能够获取锁,等待获取锁的线程将会被阻塞并处于等待(waiting)状态。

std::shared_mutex:共享读写锁,支持多个读线程同时访问,但只允许一个写线程访问。std::shared_mutex实现读写分离,读锁需要跟踪读者数量,锁定/解锁开销更大。写操作仍然是独占的,写锁性能与std::mutex相当。

nsync_mutex_t:google开源并发库nsync的互斥锁。

nsync_rwlock_t:google开源并发库nsync的读写锁,即write mode下使用lock,read mode下使用rlock。

附nsync库地址:GitHub - google/nsync: nsync is a C library that exports various synchronization primitives, such as mutexesnsync is a C library that exports various synchronization primitives, such as mutexes - GitHub - google/nsync: nsync is a C library that exports various synchronization primitives, such as mutexeshttps://github.com/google/nsync

 测试机器情况

qmutex和stdmutex性能对比,c++,开发语言,linux

测试结果

本次测试使用std::unorder_map。

exp.1

os: linux

threads: 3读1写

hashmap length: 36675

read times: 10000 / thread

write times: 10000 / thread

epoch: 4

加锁方式

cost1

cost2

cost3

cost4

avg

std::mutex

9186 us

6446 us

6415 us

6403 us

7112 us

pthread_mutex_t

24062 us

19120 us

16866 us

17141 us

19297 us

9730 us

18748 us

16933 us

17394 us

15701 us

pthread_rwlock_t

21546 us

19722 us

18900 us

20660 us

20207 us

13019 us

10260 us

10149 us

10330 us

10939 us

pthread_spinlock_t

24909 us

24051 us

20031 us

20241 us

22308 us

10846 us

6420 us

6395 us

6393 us

7513 us

nsync_mutex_t

29628 us

28371 us

25245 us

25253 us

27124 us

9267 us

6562 us

6501 us

6500 us

7207 us

nsync_rwlock_t

(写lock, 读rlock mix)

25121 us

24177 us

21694 us

21674 us

23166 us

13293 us

10319 us

10439 us

10589 us

11160 us

std::shared_mutex

13134 us

13138 us

10487 us

10671 us

11857 us

exp.2

os: linux

threads: 3读1写

hashmap length: 36675

read times: 10000 / thread

write times: 1000 / thread

epoch: 4

加锁方式

cost1

cost2

cost3

cost4

avg

std::mutex

4965 us

4612 us

4630 us

4646 us

4713 us

pthread_mutex_t

12305 us

9831 us

10552 us

10900 us

10897 us

4968 us

9776 us

10180 us

10894 us

8954 us

pthread_rwlock_t

13780 us

13561 us

13517 us

13342 us

13550 us

8906 us

8408 us

8443 us

8428 us

8546 us

pthread_spinlock_t

13822 us

12730 us

14003 us

13518 us

13518 us

5214 us

4691 us

4666 us

4754 us

4831 us

nsync_mutex_t

18121 us

17780 us

18220 us

18829 us

18237 us

4699 us

4534 us

4496 us

4675 us

4601 us

nsync_rwlock_t

(写lock, 读rlock mix)

16456 us

16375 us

15957 us

16975 us

16440 us

8821 us

8800 us

8592 us

8473 us

8671 us

std::shared_mutex

8891 us

8565 us

8748 us

8559 us

8690 us

exp.3

os: linux

threads: 4读2写

hashmap length: 36675

read times: 10000 / thread

write times: 1000 / thread

epoch: 4

加锁方式

cost1

cost2

cost3

cost4

avg

std::mutex

7697 us

6348 us

6094 us

6086 us

6556 us

pthread_mutex_t

21670 us

18028 us

18288 us

18539 us

19131 us

6684 us

18915 us

18855 us

18791 us

15811 us

pthread_rwlock_t

20989 us

20792 us

20321 us

20618 us

20680 us

16854 us

16228 us

15962 us

16417 us

16365 us

pthread_spinlock_t

21585 us

22893 us

21294 us

22650 us

22105 us

7055 us

7292 us

6142 us

7366 us

6963 us

nsync_mutex_t

24586 us

24548 us

24948 us

25607 us

24922 us

6602 us

6008 us

5980 us

5985 us

6143 us

nsync_rwlock_t

(写lock, 读rlock mix)

22541 us

23444 us

22741 us

22859 us

22896 us

17076 us

15687 us

16011 us

15786 us

16140 us

std::shared_mutex

16847 us

16008 us

15922 us

16075 us

16213 us

exp.4

os: linux

threads: 6读3写

hashmap length: 36675

read times: 10000 / thread

write times: 3000 / thread

epoch: 4

加锁方式

cost1

cost2

cost3

cost4

avg

std::mutex

13420 us

10872 us

10700 us

10704 us

11424 us

pthread_mutex_t

43406 us

41285 us

40320 us

40768 us

41444 us

12956 us

40143 us

38579 us

38886 us

32641 us

pthread_rwlock_t

42786 us

38810 us

39713 us

38104 us

39853 us

31753 us

29010 us

29338 us

29371 us

29868 us

pthread_spinlock_t

49577 us

44320 us

42921 us

39853 us

44167 us

16009 us

12867 us

15400 us

10944 us

13805 us

nsync_mutex_t

48348 us

47371 us

44357 us

44867 us

46235 us

13579 us

10974 us

10890 us

10833 us

11569 us

nsync_rwlock_t

(写lock, 读rlock mix)

46518 us

46523 us

45031 us

44671 us

45685 us

32345 us

29480 us

29459 us

29425 us

30177 us

std::shared_mutex

31113 us

28986 us

28955 us

31712 us

30191 us

exp.5

os: linux

threads: 8读4写

hashmap length: 36675

read times: 10000 / thread

write times: 3000 / thread

epoch: 4

加锁方式

cost1

cost2

cost3

cost4

avg

std::mutex

18684 us

15223 us

15186 us

15191 us

16071 us

pthread_mutex_t

61733 us

55128 us

52081 us

52337 us

55319 us

18807 us

53878 us

51183 us

50275 us

43535 us

pthread_rwlock_t

58043 us

55728 us

54218 us

55093 us

55770 us

47133 us

44446 us

47107 us

43977 us

45665 us

pthread_spinlock_t

73558 us

65183 us

58573 us

61395 us

64677 us

20976 us

20723 us

17269 us

16682 us

18542 us

nsync_mutex_t

64249 us

61961 us

59575 us

60961 us

61686 us

19168 us

15756 us

15542 us

15591 us

16514 us

nsync_rwlock_t

(写lock, 读rlock mix)

66496 us

63230 us

59097 us

60990 us

62453 us

48564 us

45194 us

45920 us

45330 us

46252 us

std::shared_mutex

47652 us

44839 us

44833 us

44265 us

45397 us

实验结论 

1.按照keys的批次加锁的情况来看,pthread_mutex_t是性能最差的(剔除异常的cost1数据),其次由于共享资源的锁竞争较小,pthread_rwlock_t和std::shared_mutex相差不大表现最好的是nsync_mutex_t。就目前的实验参数来看,std::mutex和nsync_mutex_t还要略优于pthread_spinlock_t。nsync_rwlock_t、std::shared_mutex和pthread_rwlock_t在批量加锁的性能表现上是十分相近的。建议在一般情况下,使用std::mutex即可,尽量不用读写锁

2.pthread_mutex_t、pthread_rwlock_t、pthread_spinlock_t、nsync_mutex_t、nsync_rwlock_t在对单key加锁时性能普遍较低,不推荐在单key的粒度下使用。

3.当共享资源的锁竞争很小时,rwlock的cpu性能消耗反而比spinlock要高。所以不是所有读多写少的情况下,rwlock都优于spinlock

3.1分析:从spinlock和rwlock的功能上分析,前者只允许一个线程访问共享资源,其余线程均是忙等待;后者则允许多个读者同时访问,绝对限制只有一个线程可以作为写者。当读者访问资源时,写者必须忙等待,反之亦然。只从功能描述上分析,rwlock从功能上应该比spinlock性能要好。而cache数据结构一般使用hash表维护,当散列函数比较理想时,锁竞争发生的概率可能很小。由此猜测rwlock造成的性能下降,可能是因为rwlock的自身上锁解锁的cpu消耗要比spinlock高导致的。在上锁时,pthread_rwlock_wrlock和pthread_rwlock_rdlock会引入线程阻塞和切换的开销,而pthread_spin_lock会自旋等待锁,不会阻塞线程,减少了线程切换的开销。

4.在pthread系列中,读写锁的性能要优于互斥锁;但在nsync系列中,互斥锁要优于读写锁。

5.std::mutex在linux环境下性能比pthread_mutex_t要好的原因有以下几点:

  • std::mutex采用自旋锁+条件变量实现,在锁持有时间短的情况下可以避免上下文切换。而pthread_mutex_t直接使用操作系统mutex,依赖系统调用获取锁,上下文切换开销较大。

解释:GCC标准库实现的std::mutex,在Linux下默认会使用PTHREAD_MUTEX_ADAPTIVE_NP类型的pthread mutex作为底层实现。这种底层实现可以让std::mutex在不同的并发场景下自动选择最优的实现策略(锁竞争少时采用自旋,多时采用阻塞实现来避免频繁上下文切换)。而pthread_mutex_t是固定使用一种类型(阻塞),因此这是std::mutex在linux环境下比pthread_mutex_t更优的原因。

  • C++标准库mutex实现经过了大量优化,如GCC里采用了特定于CPU的优化指令。

  • std::mutex可以实现锁粒度更细的优化控制,避免不必要的锁竞争。文章来源地址https://www.toymoban.com/news/detail-782070.html

到了这里,关于C++ 各类mutex和读写锁性能比较的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Modern C++ std::mutex底层原理

    我时常有这样的疑问: std::mutex怎么就能保证后面的语句100%安全哪? CPU reordering就不会把这些语句重排到mutex前面执行? 而且各个CPU都是有L1、L2缓存的,如果mutex后面要访问的的变量在这些缓存中怎么办? 带着这些疑问我们先看看std::mutex是怎么实现的。 先给个图,再细说。

    2024年01月17日
    浏览(37)
  • OpenCV、Dlib 和深度学习中的各种人脸检测方法与性能比较--包含C++ 和 Python 代码实现

    文末附基于Python和C++两种方式实现的测试代码下载链接 在本教程中,我们将讨论 OpenCV、Dlib 和深度学习中的各种人脸检测方法,并对这些方法进行定量比较。我们将为以下面部检测器共享 C++ 和 Python 代码: OpenCV 中的 Haar 级联人脸检测器 OpenCV 中基于深度学习的人脸检测器。

    2024年02月10日
    浏览(48)
  • Linux各类性能分析工具用法详解

    在Linux性能分析和优化过程中,选用一个好的工具能极大的提高自己的工作效率。这里以Brendan Gregg的Linux性能工具图谱为线索,梳理了Linux系统下各个模块的性能分析工具,并对部分常用工具的用法进行了详细说明。掌握这些工具,可以极大的提高开发者程序性能优化的效果和

    2024年02月11日
    浏览(53)
  • 开源与专有软件:比较与对比

    🌷🍁 博主猫头虎 带您 Go to New World.✨🍁 🦄 博客首页——猫头虎的博客🎐 🐳《面试题大全专栏》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺 🌊 《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐 🌊 《100天精通Golang(基础入门篇)》学会Golang语言

    2024年02月11日
    浏览(59)
  • C++ Qt开发:Charts绘制各类图表详解

    Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍 TreeWidget 与 QCharts 的常用方法及灵活运用。 在之前的文章中笔者介绍了如何使

    2024年02月04日
    浏览(47)
  • C# XML 的读写以及和JSON对比

    通过我们进行跨平台传输,我们需要把某一个平台特有的数据类型转化为一种通用的数据类型序列化和反序列化 通用形式有两种: 《1》JSON:是一种以键值形式组成 《2》XML:可扩展标记语言 XML文件格式要求: 《1》头部需要有XML标记; 《2》每一个XML文件有且只有一个 《

    2024年02月14日
    浏览(42)
  • 【STM32学习】——STM32-I2C外设&硬件读写MPU6050&软硬件读写波形对比

    目录 前言 一、I2C外设 二、硬件I2C操作流程 1.主机发送时序 3.其他时序

    2024年02月10日
    浏览(49)
  • Java多线程:读写锁和两种同步方式的对比

    读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务),但是效率非常低。所以在JDK中提供了一种读写锁ReentrantReadWriteLock,使用它可以加快运行效率。 读写锁表

    2023年04月09日
    浏览(41)
  • AI编程,详细比较GitHub Copilot对比Amazon CodeWhisperer

    本文将比较GitHub Copilot和Amazon CodeWhisperer两个AI编码助手。 微信搜索关注《Python学研大本营》,加入读者群,分享更多精彩 GitHub Copilot和Amazon CodeWhisperer是采用人工智能技术驱动的编码助手,它们将自动完成编码功能提升到一个全新的水平。在最佳状态下,它们可以根据开发者

    2024年02月04日
    浏览(52)
  • JAVA终极对比Python:分析和比较处理大数据的能力

    Java 是一种编译型语言,代码在运行之前首先需要被编译成字节码,然后在Java虚拟机(JVM)上运行。这通常可以提高执行速度。 Python 是一种解释型语言,代码在运行时由解释器逐行解释执行。这使得Python的启动速度相对较慢。 Java 虚拟机(JVM)可以执行即时编译(Just-In-Ti

    2024年01月18日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包