跟我一起做面试题-linux线程编程(7)

一直以来难以调试多线程,在网上搜索得知一种多线程调试的方法

一直觉得Linux下的多线程调试是很麻烦的,因为一般大一点的程序线程会很多,通过gdb的info thread命令看全都是系统调用,看不到详细的方法,至少我看到是这样的...如果用thread id跟进每个thread去bt,是件相当痛苦的事情,特别是你info thread看到近百个线程的时候T_T.而且大多时候等待重现问题或重启程序的时间代价是相当高的,在程序运行的情况下查看thread堆栈情况就显得 很重要了.

其实有pstack这个命令问题就很简单了,pstack具体用法man pstack.

gdb+pstack:

通过ps获取程序pid.

gdb processname pid,调试在运行程序.

info thread输出的线程信息类似:

(gdb) info thread
79 Thread 0x2547b90 (LWP 22267)? 0x00795410 in __kernel_vsyscall ()?
78 Thread 0x5c6eb90 (LWP 22268)? 0x00795410 in __kernel_vsyscall ()?
77 Thread 0x2f48b90 (LWP 22270)? 0x00795410 in __kernel_vsyscall ()?
76 Thread 0x94e3b90 (LWP 22272)? 0x00795410 in __kernel_vsyscall ()?
75 Thread 0x3949b90 (LWP 22287)? 0x00795410 in __kernel_vsyscall ()?
74 Thread 0x3d4ab90 (LWP 22393)? 0x00795410 in __kernel_vsyscall ()?
73 Thread 0x414bb90 (LWP 22394)? 0x00795410 in __kernel_vsyscall ()

从上面来看,只能看到系统调用,这很难判断各个线程在干什么,如果你有别的方法能在gdb中直观的查看到各个线程在跑啥,求告知 : )

我的办法是借助pstack来查看,当然,前提是你的Linux上装了这个工具,但大部分Linux上应该是有的.

pstack pid,你会得到很多信息:

pstack 22266
Thread 78 (Thread 0x2547b90 (LWP 22267)):
#0? 0x00795410 in __kernel_vsyscall ()
#1? 0x00b5eaa6 in nanosleep () from /lib/libc.so.6
#2? 0x00b5e8cf in sleep () from /lib/libc.so.6
#3? 0x08134a3a in RemoveLog(void*) ()
#4? 0x0085e832 in start_thread () from /lib/libpthread.so.0
#5? 0x00b9ee0e in clone () from /lib/libc.so.6
Thread 77 (Thread 0x5c6eb90 (LWP 22268)):
#0? 0x00795410 in __kernel_vsyscall ()
#1? 0x00b5eaa6 in nanosleep () from /lib/libc.so.6
#2? 0x00b5e8cf in sleep () from /lib/libc.so.6
#3? 0x08134a3a in RemoveLog(void*) ()
#4? 0x0085e832 in start_thread () from /lib/libpthread.so.0
#5? 0x00b9ee0e in clone () from /lib/libc.so.6


如我看到下面这个线程,其他线程的CProcess::readDevices都被lock住了,因为线程安全
CProcess::readDevices是加锁的,其他很多线程都是卡在CProcess::wrLock()
()或CProcess::rdLock() (),而下面这个线程明显是罪魁祸首,别问我为什么,因为我无法解释1+1为什么=2...

Thread 23 (Thread 0x631ffb90 (LWP 1161)):
#0? 0x00795410 in __kernel_vsyscall ()
#1? 0x00b979d1 in select () from /lib/libc.so.6
#2? 0x0812f1a2 in Sleep(int) ()
#3? 0x080598e6 in CProcess::readDevices(FluxControl::DeviceArray const&) ()
#4? 0x081281a1 in FluxControlImpl::readDevices(FluxControl::DeviceArray const&) ()
#5? 0x0813b2f2 in _0RL_lcfn_28D700E3085A57CA_30000000(omniCallDescriptor*, omniServant*) ()
#6?
0x0093b14d in omniCallHandle::upcall(omniServant*,
omniCallDescriptor&) () from
/export/home/tools/omniORB-4.0.7/lib/libomniORB4.so.0
#7? 0x0813c48e in FluxControl::_impl_FluxDeviceConf::_dispatch(omniCallHandle&) ()
#8?
0x009269bf in omni::omniOrbPOA::dispatch(omniCallHandle&,
omniLocalIdentity*) () from
/export/home/tools/omniORB-4.0.7/lib/libomniORB4.so.0
#9?
0x0090a963 in omniLocalIdentity::dispatch(omniCallHandle&) () from
/export/home/tools/omniORB-4.0.7/lib/libomniORB4.so.0
#10 0x0095aa92 in omni::GIOP_S::handleRequest() () from /export/home/tools/omniORB-4.0.7/lib/libomniORB4.so.0

找到这里在pstack中无法关联到具体的代码,这个时候回头看gdb,gdb是可以看到的 : ).


面pstack得到的问题线程是Thread 23 (Thread 0x631ffb90 (LWP
1161)),但这时你用gdb查看程序pid的时候线程号不一定还是thread
23,以为其他没有被锁的线程也会在竞争,序号是会变的,但是Thread 0x631ffb90 是不会变的,所以gdb processname
pid,然后info thread查看线程,然后在输出的线程信息中搜索0x631ffb90,你就会找到对应的线程,然后在gdb中执行thread
threadid,然后就可以进入这个线程查看了.

原文地址:http://dy601601.blog.163.com/blog/static/12978026320125353956724/

时间: 2024-07-29 16:38:59

跟我一起做面试题-linux线程编程(7)的相关文章

跟我一起做面试题-linux线程编程(5)

如题所述: 生产者消费者问题 这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若 干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲 区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经 装满产品且尚未被取走的缓冲区中投放产品. 1 #include <stdio.h> 2

跟我一起做面试题-linux线程编程

如题所述: 编写程序完成如下功能: 1)有一int型全局变量g_Flag初始值为0: 2) 在主线称中起动线程1,打印“this is thread1”,并将g_Flag设置为1 3) 在主线称中启动线程2,打印“this is thread2”,并将g_Flag设置为2 4) 线程序1需要在线程2退出后才能退出 5) 主线程在检测到g_Flag从1变为2,或者从2变为1的时候退出 #include <stdio.h> #include <stdlib.h> #include &l

跟我一起做面试题-linux线程编程(4)

如题所述: 有四个线程1.2.3.4.线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD.初始都为空.现要让四个文件呈如下格式: A:1 2 3 4 1 2.... B:2 3 4 1 2 3.... C:3 4 1 2 3 4.... D:4 1 2 3 4 1.... 请设计程序. 1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #in

跟我一起做面试题-linux线程编程(3)

如题所述: 编写一个程序,开启3个线程,这3个线程的ID分别为A.B.C,每个线程将自己的ID在屏幕上打印10遍,要求输出结果必须按ABC的顺序显示:如:ABCABC….依次递推. ----------------------------------------------------------------------------------------------------------------- 用pthread_cond_signal,理论上会引起本该得到信号的线程一直处于饥饿状态,

Linux线程编程之信号处理

前言 Linux多线程环境中的信号处理不同于进程的信号处理.一方面线程间信号处理函数的共享性使得信号处理更为复杂,另一方面普通异步信号又可转换为同步方式来简化处理. 本文首先介绍信号处理在进程中和线程间的不同,然后描述相应的线程库函数,在此基础上给出一组示例代码,以讨论线程编程中信号处理的细节和注意事项.文中涉及的代码运行环境如下: 本文通过sigwait()调用来“等待”信号,而通过signal()/sigaction()注册的信号处理函数来“捕获”信号,以体现其同步和异步的区别. 一  概念

Linux线程编程之生产者消费者问题

前言 本文基于顺序循环队列,给出Linux生产者/消费者问题的多线程示例,并讨论编程时需要注意的事项.文中涉及的代码运行环境如下: 本文假定读者已具备线程同步的基础知识. 一  顺序表循环队列 1.1 顺序循环队列定义 队列是一种运算受限的先进先出线性表,仅允许在队尾插入(入队),在队首删除(出队).新元素入队后成为新的队尾元素,元素出队后其后继元素就成为队首元素. 队列的顺序存储结构使用一个数组和两个整型变量实现,其结构如下: 1 struct Queue{ 2 ElemType elem[M

linux 线程编程详解

1.线程的概念: 线程和进程有一定的相似性,通常称为轻量级的进程 同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等.但同一进程中的多个线程都有自身控制流 (它自己的指令计数器和cpu时钟)和各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage). 一个进程可以有很多线程,每条线程并行执行不同的任务. 线程可以提高应用程序在多核环境下处理诸如文件I/O或者s

Linux 线程编程2.0——线程同步-互斥锁

当我们需要控制对共享资源的存取的时候,可以用一种简单的加锁的方法来控制.我们可以创建一个读/写程序,它们共用一个共享缓冲区,使用互斥锁来控制对缓冲区的存取. 函数 pthread_mutex_init()用来生成一个互斥锁.其函数原型如下: #include<pthread.h> int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr): 第一个参数是互斥变量

嵌入式linux面试题解析(三)——Linux应用编程部分一

嵌入式linux面试题解析(三)--Linux应用编程部分一 1.TCP与UDP的区别 TCP:是面向连接的流传输控制协议,具有高可靠性,确保传输数据的正确性,有验证重发机制,不会出现丢失或乱序. UDP:是无连接的数据报服务,不对数据报进行检查与修改,无须等待对方的应答,会出现分组丢失.重复.乱序,但具有较好的实时性,UDP段结构比TCP的段结构简单,因此网络开销也小. 2.流量控制和拥塞控制 拥塞控制    网络拥塞现象是指到达通信子网中某一部分的分组数量过多,使得该部分网络来不及处理,以致