linux - unix环境高级编程的多线程死锁例子没看懂,求解释?
天蓬老师
天蓬老师 2017-04-17 16:01:24
0
1
439

unix环境高级编程第三版323面到325面那个多线程操作哈希表的例子。

我不懂的是为什么最后释放节点的时候,作者先对节点加锁获取其引用次数,次数为1需要删除节点。然后作者后面解释到,需要释放这个锁才能对哈希表加锁,才能删除节点。请问这是为什么?在这种情况下不就是先获得哈希表锁再获得节点锁,和前面的添加节点加锁顺序相反,还有可能造成死锁啊。



提问者更新:

(非常感谢乌合之众兄的回答。这里是我自己看错了,添加节点的时候也是先锁哈希表再锁节点的;为了避免死锁,在释放节点的时候互斥嵌套的时候也要先锁哈希表,再锁节点的。因为书上这么说是对的,只是解释的太模糊了。岁数大了,眼神不好使呀。)

天蓬老师
天蓬老师

欢迎选择我的课程,让我们一起见证您的进步~~

reply all (1)
Peter_Zhu

这里是有原因的,先来看看大致的流程结构

fh 哈希表(链表解决散列冲突) foo 哈希表节点(指向对象) foo_alloc 申请节点 1、申请节点内存 2、插入到哈希表 2.1、哈希表加锁(hashlock) 2.2、插入新节点 2.3、节点加锁(此时节点已经添加到哈希表中了) 2.4、哈希表解锁 2.5、其他初始化动作 2.6、节点解锁 foo_hold 拿住节点 1、节点加锁(所有节点都应该是通过foo_alloc获取的,所以使用的时候已经在哈希表中了) 2、节点引用计数加1 2、节点解锁 foo_find 查找节点 1、哈希表加锁(避免此时有申请或者释放节点) 2、查找节点 3、哈希表解锁 foo_rele 释放节点 1、节点加锁 2、判断节点引用计数是否为1 2.1、节点引用计数为1,做以下动作 a. 节点解锁,哈希表加锁 b. 节点加锁 判断此时节点引用计数是否为1,不为1则将引用计数减1 然后解锁节点、解锁哈希表,函数返回 c. 从哈希表中移除节点 d. 哈希表解锁 e. 节点解锁 f. 释放节点内存(需要释放锁) 2.2、节点引用计数不为1 节点引用计数减1 节点解锁

几个函数大致就是这样的结构,前面的就不画图了,最后foo_rele画一个图详细的说一下。
如果在第一次判断引用计数为1的时候,不对节点进行解锁,直接从哈希表中摘除并进行释放,这里会出问题。

因为你需要摘除节点,就必须对哈希表进行加锁,如果没有加锁,则可以有一个线程调用了foo_find拿到了这个节点。又因为释放节点必须先对其解锁,那么就有可能你这里刚解锁,另一个线程通过foo_hold对其进行使用了。然后节点被销毁,可是还有一个线程正在引用它。

线程A: 节点加锁---> --->节点解锁 ---->节点销毁 线程B: foo_find拿到节点 -->foo_hold使用节点 -->引用节点出错

添加节点的时候,节点都是新申请的,不存在被其他线程使用的情况,所以不会造成死锁。

    Latest Downloads
    More>
    Web Effects
    Website Source Code
    Website Materials
    Front End Template
    About us Disclaimer Sitemap
    php.cn:Public welfare online PHP training,Help PHP learners grow quickly!