• 多线程+fork 引发的bug查找


    1. 问题描述

        某个server SA是一个多线程服务器,主线程会调用fork,再exec生成工作进程SB。

        实际上,SA的主线程fork出了一个子线程,但没有执行exec。

    # ps ajxf | grep r2server
    14022 28342 28341 14022 pts/2    28341 S+       0   0:00  |       \_ grep r2server
        1 28046 28037  3823 ?           -1 Sl       0  31:25 ./r2server ../conf/r2server.conf
    28046 28075 28037  3823 ?           -1 S        0   0:00  \_ ./r2server ../conf/r2server.conf

    2. 问题定位

      2.1 用pstack观察2个进程当前stack状态。

    # pstack 28075
    #0  0x00007f40f24bf264 in __lll_lock_wait () from /lib64/libpthread.so.0
    #1  0x00007f40f24ba508 in _L_lock_854 () from /lib64/libpthread.so.0
    #2  0x00007f40f24ba3d7 in pthread_mutex_lock () from /lib64/libpthread.so.0
    #3  0x000000000043b407 in r2::log::LogFactory::log_printf(char const*, char const*, int, char const*, int, char const*, ...) ()

    发现被lock住了。

    google “pthread_mutex_lock owner”找到文献 https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Deadlocks,

    安装上面的方法,定位:

    f 3

    (gdb) info reg
    rax            0xfffffffffffffe00       -512
    rbx            0x7517a0 7673760
    rcx            0xffffffffffffffff       -1
    rdx            0x7f40d9ff86bf   139916512036543
    rsi            0x80     128
    rdi            0x753fb0 7684016
    rbp            0x753fb0 0x753fb0
    rsp            0x7f40d9ff85c0   0x7f40d9ff85c0
    r8             0x753fb0 7684016

    (gdb) p *(pthread_mutex_t*)0x753fb0
    $1 = {__data = {__lock = 2, __count = 0, __owner = 28049,

    说明当前线程的在等待一个锁,该锁被28049占有了。

    # pstack 28049
    Thread 1 (process 28049):
    #0  0x00007f40f1a65ef3 in epoll_wait () from /lib64/libc.so.6

    说明该线程已经释放了这个锁。

    因此原因 是多线程+fork引起的bug:进程组28046里的主线程28046调用fork的时候,此时线程28049占用了一个锁A(正在打log),创建了子进程28075。

    子进程执行exec前的代码,遇到log_printf调用,去申请锁A。因为锁A是被lock的,因此该进程死锁,执行不了到exec。

    进程组28046的线程28049打完log后,释放了锁A(进程组28046和进程28075是两个不同的进程空间,有不同的page table。此时释放锁A会采用copy on write技术,创建一个新的锁A),继续正常执行。

    根本原因:由于多线程的存在,某个线程占用了一个锁,因此fork的时候,fork出来的进程地址空间包含了这个被占用的锁。如果在exec之前,调用再申请这个锁,会导致死锁。

    3. 解决方案

    1. 多线程 or fork二选一。

    2. 多线程+fork的时候,fork到exec之间只调用的async—signal function (man 7 singal),因为此时进程状态是unsafe的。

    参考文献:

    http://www.linuxprogrammingblog.com/threads-and-fork-think-twice-before-using-them

    https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Deadlocks

  • 相关阅读:
    禁止使用U盘和移动硬盘
    Linux下Red5安装和配置
    ORACLE 10g下载地址
    常挂在美国人嘴边的最酷口语
    关于oracle中spfile和pfile的一个实验
    nginx搭建流媒体服务器
    powerDesigner 把name项添加到注释(comment),完美方案!
    memcached全面剖析–PDF总结篇
    PD 导出SQL语句
    本地读取虚拟机系统中的资源
  • 原文地址:https://www.cnblogs.com/Torstan/p/4915689.html
Copyright © 2020-2023  润新知