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

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

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



提问者更新:

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

天蓬老师
天蓬老师

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

全部回复(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使用节点      -->引用节点出错

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

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!