美文网首页C语言&嵌入式
调试陷入死循环程序的方法

调试陷入死循环程序的方法

作者: guotianqing | 来源:发表于2018-08-20 22:29 被阅读33次

    概述

    应用程序陷入死循环后,界面可能不会有任何输出,所有的业务也不通,不易定位。

    陷入死循环的程序占用的cpu使用率较高,通常可以通过使用top命令看出来。

    对于多线程的程序,需要耐心调试,本文给出笔者近期使用的方法。

    调试步骤

    测试程序

    编写一个多线程进入死循环的测试程序,如下:

    #include <stdio.h>
    #include <pthread.h>
    
    #define MAX_THREAD 4
    
    static void dead_loop(void)
    {
        while(1) {
            continue;
        }
    }
    
    int main(void)
    {
        int i = 0;
        pthread_t ntid[MAX_THREAD];
    
    //    dead_loop();
        for (i = 0; i < 4; i++) {
            if (pthread_create(&ntid[i], NULL, (void *)dead_loop, NULL) == 0) {
                printf("pthread id = %u\n", ntid[i]);
            }
        }
        while(1) {
            pause();
        }
    
        return 0;
    }
    

    编译:gcc -g while_test.c -pthread

    该程序运行后进入死循环,下面分析调试方法。

    确定陷入死循环的程序

    • 程序运行后会打印各id号,然后无任何输出,程序陷入了死循环

    • ps确认程序仍在运行,ps也可以查看进程状态

    • ps -T 查看进程中包含的线程

    -> % ps -eT | grep a.out
    10703 10703 pts/0    00:00:00 a.out
    10703 10704 pts/0    00:00:39 a.out
    10703 10705 pts/0    00:00:40 a.out
    10703 10706 pts/0    00:00:41 a.out
    10703 10707 pts/0    00:00:40 a.out
    
    • ps -eL 查看各线程的运行时间,可以辅助确认处于死循环的线程
    -> % ps -eL | grep a.out
    10703 10703 pts/0    00:00:00 a.out
    10703 10704 pts/0    00:01:33 a.out
    10703 10705 pts/0    00:01:34 a.out
    10703 10706 pts/0    00:01:31 a.out
    10703 10707 pts/0    00:01:34 a.out
    
    • top查看进程cpu使用率
    • top -H 查看各线程的使用率
    • top界面下按1查看各个cpu的占用率
    -> % top -H
    top - 21:47:24 up  6:18,  3 users,  load average: 0.90, 0.64, 0.60
    Threads: 402 total,   5 running, 396 sleeping,   0 stopped,   1 zombie
    %Cpu0  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu1  : 99.7 us,  0.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu2  : 99.7 us,  0.3 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    %Cpu3  :100.0 us,  0.0 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
    KiB Mem:   1024256 total,  1002628 used,    21628 free,   101592 buffers
    KiB Swap:  1046524 total,     4456 used,  1042068 free.   342212 cached Mem
    
      PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                       
    10796 yao       20   0   35068    608    544 R 99.9  0.1   0:15.59 a.out                                                         
    10797 yao       20   0   35068    608    544 R 99.9  0.1   0:15.68 a.out                                                         
    10794 yao       20   0   35068    608    544 R 99.3  0.1   0:15.66 a.out                                                         
    10795 yao       20   0   35068    608    544 R 99.3  0.1   0:15.50 a.out  
    

    调试程序死在何处

    使用gdb调试程序:

    • 使用attach pid 进入之前查看到的进程
    • 使用info threads 查看线程信息,可以看到四个线程的运行位置
    • 使用thread 序号 进入指定序号的线程,打印出运行的位置
    • 使用bt 打印栈信息,查看函数调用关系
    GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
    Copyright (C) 2014 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i686-linux-gnu".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/gdb/bugs/>.
    Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.
    For help, type "help".
    Type "apropos word" to search for commands related to "word".
    (gdb) attach 10848
    Attaching to process 10848
    Reading symbols from /home/yao/work/util/a.out...done.
    Reading symbols from /lib/i386-linux-gnu/libpthread.so.0...Reading symbols from /usr/lib/debug//lib/i386-linux-gnu/libpthread-2.19.so...done.
    done.
    [New LWP 10852]
    [New LWP 10851]
    [New LWP 10850]
    [New LWP 10849]
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1".
    Loaded symbols for /lib/i386-linux-gnu/libpthread.so.0
    Reading symbols from /lib/i386-linux-gnu/libc.so.6...Reading symbols from /usr/lib/debug//lib/i386-linux-gnu/libc-2.19.so...done.
    done.
    Loaded symbols for /lib/i386-linux-gnu/libc.so.6
    Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug//lib/i386-linux-gnu/ld-2.19.so...done.
    done.
    Loaded symbols for /lib/ld-linux.so.2
    0xb7718cb0 in ?? ()
    (gdb) info threads 
      Id   Target Id         Frame 
      5    Thread 0xb7530b40 (LWP 10849) "a.out" dead_loop () at while_test.c:10
      4    Thread 0xb6d2fb40 (LWP 10850) "a.out" dead_loop () at while_test.c:10
      3    Thread 0xb652eb40 (LWP 10851) "a.out" dead_loop () at while_test.c:10
      2    Thread 0xb5d2db40 (LWP 10852) "a.out" dead_loop () at while_test.c:10
    * 1    Thread 0xb7531700 (LWP 10848) "a.out" 0xb7718cb0 in ?? ()
    (gdb) bt
    #0  0xb7718cb0 in ?? ()
    #1  0xb754ca83 in __libc_start_main (main=0x8048552 <main>, argc=1, argv=0xbf999c34, init=0x80485d0 <__libc_csu_init>, 
        fini=0x8048640 <__libc_csu_fini>, rtld_fini=0xb7729180 <_dl_fini>, stack_end=0xbf999c2c) at libc-start.c:287
    #2  0x08048471 in _start ()
    (gdb) thread 2
    [Switching to thread 2 (Thread 0xb5d2db40 (LWP 10852))]
    #0  dead_loop () at while_test.c:10
    10      }
    (gdb) bt
    #0  dead_loop () at while_test.c:10
    #1  0xb76e7f70 in start_thread (arg=0xb5d2db40) at pthread_create.c:312
    #2  0xb761ebee in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:129
    

    结论

    对于陷入死循环的程序,服务器一般会频繁地散热,在多线程业务复杂的程序中有可能出现。

    开发人员在编程时需要考虑全面细致,尽量注意到可能的异常,很多死循环是因为没有预料到的异常引入的。

    对于陷入死循环的程序,稳位步骤,逐步调试,并不难定位原因。

    相关文章

      网友评论

        本文标题:调试陷入死循环程序的方法

        本文链接:https://www.haomeiwen.com/subject/wsyriftx.html