发布于 1970-01-01 08:00
  • 1 个回答
    • 这里是有原因的,先来看看大致的流程结构

      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使用节点      -->引用节点出错

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

      2022-11-26 19:16 回答
    撰写答案
    今天,你开发时遇到什么问题呢?
    立即提问
    PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有