一个fork引起的“穿越”事件。

    同事最近调程序,遇到一个非常诡异的现象。一个全局变量,在没任何其他赋值的情况下,自己就莫名其妙地发生了改变。开始怀疑是消息队列出了问题。因为该程序与另一个庞大的程序通过消息队列进行通信。消息队列调试了N天,无果。

    又开始怀疑是不是内存或堆栈出错。于是仔细找了所有的数组、变量及malloc函数,还是没发现有不对的地方。况且,每次该变量值变化的一模一样,并不像内存泄露导致的程序异常。

    百思不得其解。

    后来,经过漫长的跟踪,屏蔽了其他很多语句后,终于发现了蛛丝马迹。在某一个语句后,一个print语句执行了两遍。该语句前有个fork函数,它启动了一个子进程,该子进程仅仅进行了一个写文件的操作。仔细一看,fork的子进程没有退出语句。

pid = fork();  
        // son process create here, exact copy from parent process  
        // son process will execute the main funciton after parent process  
        if(pid<0) {  
                printf("return");  
                return 0;  
        }  
        if(pid==0) {  
              。。。。
        }else {  
                。。。
        }  
      现在很多实现并不执行一个父进程数据段、栈和堆的完全复制。作为替代,使用写时复制(Copy-On-Write,COW)。这些区域由父子进程共享,而且内核将它们的访问权限改变为只读。如果父子进程中的任一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常是虚拟存储器系统的一页。没有退出,则子进程与父进程一起继续运行,一前一后。所以,导致父进程对全局变量赋值为1,而下一时刻子进程运行到这里,检查子进程的内存区域该变量为0,于是该变量前一时刻为0,后一时刻又变成了1,最终导致程序结果哭笑不得。

      这就像《黑衣人3》里J穿越到过去,在最后阿波罗升空的时刻,在野兽杀他的时候又进行了数次的穿越,使得野兽始终在那里杀他又杀不死他,J的状态就是一会儿生,一会儿死。又像周星驰在《大话西游》里月光宝盒进行了几次穿越,看到白晶晶一会儿生一会儿死。当然外国的时空穿越器比中国的要可靠,月光宝盒在进行了两次穿越后出了故障到了五百年前。

      好了,耗时两周多的怪异现象终于有了定论。我们可以总结出几点经验:

    1. 调试程序要学会抽丝剥茧一样,排除不想干的元素,使得问题简单化;

    2. 学会定位。定位到某行代码,更能帮助找到原因所在。

    3. 丰富的编程经验也是必不可少。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值