不经意间的死锁,很强大

        好久没有写过博客了 , 上一次写博客仿佛还是在去年的萌新时期。

        中秋节到了 , 趁着假期没有什么招聘赶紧充电 , 所以我拿来了我的玩具web服务器搞了起来。

        但是在不经意间写了一个大大的bug , 和死锁有关系。其中原因是这样的 , 如大家所知 , server这种类一般都被设计成为单例模式,而单例模式中饿汉模式过于简单 , 因此想搞一波来个线程安全的懒汉模式 (各位看客老爷们:简直是作死!), 所以用到了锁在这里放码给大家看一下 , 防止大家以后写出一些很大的bug而被迫加班导致幸福感暴跌! :- )

          在这里我们先看一下懒汉模式的核心代码

          

   HttpServer的构造 析构函数私有,以及Instance是一个静态指针,GetInstance DestoryInstance这些接口也是静态方法。顺便给大家科普一波单例模式,是为了确保一个类只被实例化出一个对象。而懒汉模式,之所以称为懒汉就是等有需求时才创建,是不是听起来就很懒?这里为了确保线程安全我使用了Pthread库的线程锁来保证操作的原子性。

    所以我们的理想情况是这样子的

     构造server,进入主循环,结束主循环后开始清理工作。然而构造时却有一个作死的行为,敲黑板,重点来了!

然而在事件这一块发生了意外,server内置了一个Epoll对象,而该对象构造函数内部调用了GetInstance函数

        这个是修改后的无bug代码 , 在这之前为什么会有bug呢?

        理性分析一波 , 首先main函数调用GetInstance函数,第一次调用,所以开始构造对象,而构造函数内部又调用了Epoll的构造函数,这时注意server的构造函数还没有返回,因此Instance指针仍然为空,在这时Epoll构造内部调用GetInstance,读到的Instance依然为空,结果呢?自然是等待锁被释放,而锁呢?完蛋,锁已经在构造server时就被拿走了,现在 server构造在等待Epoll构造函数执行完后执行其他逻辑,而Epoll在等待server构造成功之后释放锁,这不是符合我们预期的设计,反而产生了循环等待,可谓是大坑啊,大家在使用锁的时候也要仔细想一想逻辑上的缺陷,仔细想想会不会有这种请况。

        而这次得出的结论就是千万不能在单例模式的GetInstance函数中再次调用GetInstance来get未完成构造的对象(这会不会听起来太蠢了) ,但是稍微不注意,可能就会存在间接调用的情况啊!

        但是我们这些初学者不太清楚,posix线程库中除了普通的锁,还有可递归锁(可重入锁),这个问题就是典型的可以使用可递归锁来解决的问题,我后续研究一下,给出可重入锁的解决方案。

        所以还是希望这个坑在大家看过之后记住以后不再踩坑?但愿吧!

          

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值