基于锁的并发数据结构

在超越锁之前,我们将首先描述如何在一些公共数据结构中使用锁。将锁添加到数据结构以使其可用,这使得结构线程安全。当然,这样的锁究竟是如何添加的,决定了数据结构的正确性和性能。因此,我们面临的挑战。

当然,我们将很难涵盖所有的数据结构或所有增加并发性的方法,因为这是一个已经研究了多年的主题,(实际上)已经发表了数千篇研究论文。因此,我们希望能提供一种充分的介绍,让您了解所需的思维类型,并向您推荐一些好的资料来源,以便您自己进行进一步的探究。我们发现Moir和Shavit的调查是一个重要的信息来源[MS04]。

29.1并发计数器

最简单的数据结构之一就是计数器。它是一种常用的结构,具有简单的接口。我们在图29.1中定义了一个简单的非并发计数器。简单但不能扩展。如您所见,非同步计数器是一个微不足道的数据结构,需要执行少量代码。我们现在有了下一个挑战:如何使这个代码线程安全?图29.2显示了我们是如何做到这一点的。



      这个并发计数器很简单,工作正常。事实上,它遵循了一种常见到最简单和最基本的并发数据结构的设计模式:它只添加了一个单一的锁,它在调用一个操作数据结构的例程时获得,并在从调用返回时释放。以这种方式,它类似于使用监视器构建的数据结构[BH73],在这里,锁被获取并自动释放,就像您调用和返回对象方法一样。


此时,您拥有一个工作并发数据结构。您可能遇到的问题是性能。如果您的数据结构太慢,您将不得不做的不仅仅是添加一个锁;这样的优化,如果需要的话,是本章其余部分的主题。注意,如果数据结构不太慢,就完成了!没有必要做一些简单的事情

为了了解简单方法的性能成本,我们运行一个基准,每个线程更新一个共享计数器的次数;然后我们改变线程的数量。图29.3显示所花费的总时间,其中1到4个线程处于活动状态;每个线程更新计数器一百万次。这个实验是在一个iMac上运行的,有4个Intel 2.7 GHz i5 cpu;有了更多的cpu,我们希望在单位时间内完成更多的工作。

从图上的顶部行(标记为精确),您可以看到同步计数器的性能很差。单个线程可以在很短的时间内完成一百万次计数器更新(大约0.03秒),有两个线程每次更新计数器一百万次,同时导致巨大的减速(超过5秒!)它只会随着更多的线程变得更糟。

理想情况下,您希望看到线程在多个处理器上的完成速度与单个线程在一个线程上完成的速度一样快。达到这个目的被称为完美的缩放;虽然完成了更多的工作,但它是并行完成的,因此完成任务的时间没有增加。

可伸缩的计算

令人惊讶的是,研究人员已经研究了如何构建更可伸缩的计数器多年[MS04]。更令人惊奇的是,可伸缩计数器的重要性,正如最近在操作系统性能分析中所做的工作一样。 所示(B + 10);如果没有可伸缩的计数,有些工作负载在没有可伸缩计数的情况下运行,有些工作负载在运行。虽然已经开发了许多技术来解决这个问题,但是我们现在将描述一个特定的方法。在最近的研究[B+10]中引入的这个想法被认为是一个草率的计数器。这个松散的计数器可以通过多个本地物理计数器、一个CPU核心和一个全局计数器来表示一个逻辑计数器。具体来说,在一台有四个cpu的机器上,有四个本地计数器和一个全局计数器。除了这些计数器,还有锁:一个用于每个本地计数器,一个用于全局计数器。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值