《Go 并发数据结构和算法实践》学习笔记 Day 1

极客时间21天打卡活动:2023.1.16-2.5

链表的接口:

  • 插入元素
  • 删除元素
  • 读取元素

并发化改造:

  • 并发插入元素
  • 并发删除元素
  • 并发读取元素

锁,每个节点都定义一把锁。

并发插入

并发插入

区域猜想:如果某个CPU 锁定了某个节点,它就控制这个节点及其后继指针这段区域。此时只有此CPU 有权限在区域内进行写操作。

  • 往后如果要更改一个节点的后继指针,则必须先锁定这个节点(因为后继指针实际储存于这个节点中,此时每个节点带有一个Mutex锁)

只要我们能将写操作限制在部分区域,那么我们只要在区域中兼容一写多读的行为,整个数据结构就可以实现全局并发读写,并且读操作无锁。

两段链表的唯一联系是某个节点的后继指针。

并发插入的步骤:

最终正确步骤:

Insert:

  1. 找到节点A 和B,不存在则直接返回

  2. 锁定节点A ,检查A.next == B,如果为假,则解锁A 然后返回step 1

  3. 创建新节点X

  4. X.next = B; A.next = X

  5. 解锁节点A

并发插入 正确性验证的用例:

情况一:多个插入操作在Step [2,5] 之间,因为都需要争抢A 节点的锁,所以不会冲突

情况二:两个插入的B1 和A2 重合,由于有序链表的结构特点,不会冲突

情况三:多个插入操作在Step [1,2] 之间,由于我们锁定A 节点后进行检查,所以不会冲突

并发删除

由于涉及2个节点的修改,需要依次锁定2个节点。

并发删除

用例1:CPU0优先拿到A2的锁。

情况1并发错误的结果: B2 节点没有被正确删除!

并发删除用例1

原因:B1(A2) 实际是一个已经被删除的节点,G2 真正的A 节点实际应当是A1 而不是B1(A2),但是CPU1删除操作没有意识到这一点。

解决方案:如果一个节点被删除,则需要标记其为被删除状态(即所谓的逻辑删除),并且在删除操作的流程中,如果发现某个节点被删除,返回重新操作。

并发删除的步骤:

最终正确步骤:

Delete :

  1. 找到节点A 和B,不存在则直接返回

  2. 锁定节点B,检查b.marked == true,如果为真,则解锁B 然后返回step 1

  3. 锁定节点A,检查A.next != B OR a.marked,如果为真,则解锁A 和B 然后返回step 1

  4. b.marked = true;A.next = B.next

  5. 解锁节点A 和B

删除操作之所以没有将A 节点的后置节点置空,是为了避免读操作无法正确访问后继节点。

并发删除 正确性验证的用例:

情况一:多个删除前后执行,由于删除标记的存在,所以都可以正常删除

情况二:插入或删除操作发生在Step [1,2] 之间,由于我们锁定A、B 节点后进行检查,所以不会冲突

情况三:插入或删除操作发生在Step [2,5] 之间,由于我们同时锁定A 和B,A.next 和B.next 都不会改变

并发读

写操作限制在某个区域,则可实现区域内一写多读,全局多写多读。

读操作完全无锁,使用atomic 可以无限制访问节点。

参考

  1. https://time.geekbang.org/qconplus/detail/100073196
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值