Operating Systems-tep Chapter6 读书笔记

基于锁的并发数据结构

并发计数器

最简单的数据结构是计数器。此数据结构经常使用且接口简单。

简单非并发计数器

在这里插入图片描述

线程安全计数器:

在这里插入图片描述
这个并发计数器简单有效。它遵循了常见的最简单也是最基本的并发数据结构设计模式:简单地加上一个锁,即在操作该数据结构时上锁,在返回时解锁。

上面的计数器虽然保证了线程安全,但是性能方面扩展性很差,在多核CPU上运行速度很差。

性能问题可以通过sloppy counter方法来解决。sloppy counter通过多个局部物理计数器代表一个全局逻辑计数器,每个核都有一个局部物理计数器。具体的,一个4CPU的机器,有四个局部计数器和一个全局计数器。除这些计数器外,还有锁,每个局部计数器和全局计数器各自都有一把锁。

sloppy counter的基本思想如下:当运行在某个核上的某个线程想要加计数器时,它就增加核的局部计数器;通过对应的局部锁访问这个同步局部计数器。由于每个CPU都有自己的局部计数器,多CPU上的多线程就可以无竞争地更新局部计数器,因此计数器的更新是可以扩展的。

然而,为了保持全局计数器保持最新,局部值会定期提交给全局计数器,通过获取全局锁访问全局计数器并加以局部计数器的值;然后局部计数器的置重置为0.

并发链表

在这里插入图片描述

如上图所示,该代码在插入函数入口获取锁,在退出时释放锁。如果malloc()碰巧失败的话(极少数情况下),这个问题就会很棘手:这种情况下,仍然必须在插入失败之前释放锁。

我们只要稍微修改一下insert中的代码就可以解决问题。

我们将上锁的位置放在了malloc()函数之后,在操作共享链表的时候加锁,在插入完成之后再解锁,这样就完成了并发插入。

在这里插入图片描述

扩展链表:

研究人员开发出一个可以使链表并发性提高的技术:handover-hand locking(即:锁耦合)

上述技术的思想很简单。并非整个链表拥有一个锁,而是每个节点各自拥有一个锁。当遍历这个链表时,需要先获取下一个节点的锁在释放当前节点的锁。这种链表是有一定意义的:它使链表操作有了高度的并发性。但是实际上让这样的链表运行的比简单方法快还是很难的,因为在一次链表遍历中获取,释放每个节点锁的开销还是很大的。即便是非常大的链表以及大量的线程,这种方法的并发性也不太可能比简单方法的并发性高。

TIP:

在这里插入图片描述

并发队列

最简单的方法就是给队列加一把大锁。

Michael和Scott提出了一种并发队列

在这里插入图片描述

上面的并发队列使用了两个锁,一个是队首锁,一个是队尾锁,设置这两个锁是为了入队和出队的并发操作。入队函数仅访问队尾的锁,出队函数仅访问队首的锁。

并发哈希表

并发哈希表的设计是在并发链表的基础上构造,每个节点都有一个锁,这样就可以进行多个并发操作。

在这里插入图片描述

我们将使用一个锁的链表和并发哈希表做并发性能测试,发现简单的并发哈希表的扩展性非常好,但链表的扩展性很差,结果如下图:

在这里插入图片描述

TIPS:

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值