多线程对oracle进行操作,第 11 章 调试多线程应用程序

第 11 章 调试多线程应用程序

dbx 可以调试使用 Solaris 线程或 POSIX 线程的多线程应用程序。可以使用 dbx 检查每个线程的栈跟踪,恢复所有线程,step 或 next 特定线程及在线程间导航。

dbx 通过检测程序是否利用 libthread.so 来识别多线程程序。程序对 libthread.so 的使用方法有两种:一是通过 -lthread 或 -mt 对其进行显式编译;二是通过 -lpthread 对其进行隐式编译。

本章说明如何查找线程的相关信息及如何使用 dbx 线程命令调试线程。

本章由以下部分组成:

了解多线程调试

检测到多线程程序时,dbx 会尝试装入 libthread_db.so,它是一个专门用于进行线程调试的系统库,位于 /usr/lib 目录下。

dbx 是同步式的;当某个线程或轻量进程 (lightweight

process, LWP) 停止时,所有其他线程和 LWP 也会相应停止。我们有时将这种行为称作 "stop the world" 模型。

注 –

有关多线程编程和 LWP 的信息,请参见 Solaris《多线程编程指南》。

线程信息

dbx 中提供有以下线程信息:

(dbx) threads

t@1 a l@1 ?() running in main()

t@2 ?() asleep on 0xef751450 in_swtch()

t@3 b l@2 ?() running in sigwait()

t@4 consumer() asleep on 0x22bb0 in _lwp_sema_wait()

*>t@5 b l@4 consumer() breakpoint in Queue_dequeue()

t@6 b l@5 producer() running in _thread_start()

(dbx)

本机代码的每行信息由以下内容组成:

*(星号)表示该线程内发生了需要用户处理的事件。该事件通常是断点。

如果不是星号,而是 "o",则表示发生的是 dbx 内部事件。

>(箭头)表示为当前线程。

线程 id t@number 指特定线程。number 是 thr_create 传回的 thread_t 值。

b l@number 或 a l@number 表示线程绑定到指定的 LWP 或在其上处于活动状态(即操作系统可实际运行该线程)。

传递给 thr_create 的线程的“启动函数”。?() 表示启动函数未知。

线程状态(请参见表 11–1 中有关线程状态的描述。)

线程当前执行的函数。

Java 代码的每行信息由以下内容组成:

t@number,dbx 样式的线程 ID

线程状态(请参见表 11–1 中有关线程状态的描述。)

加单引号的线程名

说明线程优先级的数字

表 11–1 线程和 LWP 状态线程和 LWP 状态说明

挂起线程已被显式挂起。

可运行线程可运行,并正等待作为计算资源的 LWP。

僵停分离的线程退出 (thr_exit()) 后,在通过使用 thr_join() 重新链接之前,将一直处于僵停状态。THR_DETACHED 是在线程创建时 (thr_create()) 指定的标志。退出的非分离线程在被获得前将一直处于僵停状态。

在 syncobj 上休眠线程在给定同步对象上被阻塞。视 libthread 和 libthread_db 所提供的支持级别,syncobj 可能会如十六进制地址一般简单,也可能会包含更多的信息内容。

活动线程在某 LWP 中处于活动状态,但 dbx 无法访问该 LWP。

未知dbx 无法确定状态。

lwpstate绑定或活动线程状态具有与之关联的 LWP 的状态。

运行LWP 正在运行,但因响应另一 LWP 而同步停止。

syscall numLWP 进入给定系统调用 # 时停止。

syscall 返回 numLWP 退出给定系统调用 # 时停止。

作业控制LWP 因作业控制而停止。

LWP 挂起LWP 在内核中被阻塞。

单步递阶LWP 刚刚完成一步。

断点LWP 刚刚遇到断点。

fault numLWP 招致给定错误 #。

signal nameLWP 招致给定信号。

进程同步此 LWP 所属进程刚刚开始执行。

LWP 停止LWP 正在退出。

查看另一线程的上下文

要将查看上下文切换到另一线程,请使用 thread 命令。语法如下:

thread [-blocks] [-blockedby] [-info] [-hide] [-unhide] [-suspend] [-resume] thread_id

要显示当前线程,请键入:

thread

要切换到线程 thread_id,请键入:

thread thread_id

有关 thread 命令的更多信息,请参见thread 命令。

查看线程列表

要查看线程列表,请使用 threads 命令。语法为:

threads [-all] [-mode [all|filter] [auto|manual]]

要输出所有已知线程,请键入:

threads

要输出通常不输出的线程(僵停),请键入:

threads -all

有关线程列表的说明,请参见线程信息。

有关 threads 命令的更多信息,请参见threads 命令。

恢复执行

可以使用 cont 命令来恢复程序执行。因为线程目前使用同步断点,所以所有线程都会恢复执行。

不过,您可以使用带有 -resumeone 选项的 call 命令恢复单个线程(请参见call 命令)。

在调试多线程应用程序(其中许多线程会调用函数 lookup())时,请考虑以下两种情况:

您设置条件断点:

stop in lookup -if strcmp(name, "troublesome") == 0

当 t@1 在对 lookup() 的调用处停止时,dbx 尝试对条件求值并调用 strcmp()。

您设置断点:

stop in lookup

当 t@1 在对 lookup() 的调用处停止时,发出以下命令:

call strcmp(name, "troublesome")

调用 strcmp() 时,dbx 将会恢复调用期间内的所有线程,这与使用 next 命令进行单步执行时 dbx 所执行的操作类似。之所以这样做的原因是,如果 strcmp() 尝试抓取另一个线程拥有的锁,则仅恢复 t@1 可能会导致死锁。

在这种情况下恢复所有线程的缺点是,dbx 无法处理另一个线程(例如 t@2),从而会在调用 strcmp() 时在 lookup() 处遇到断点。它会发出类似以下之一的警告:

event infinite loop causes missed events in following

handlers:

Event reentrancy first event BPT(VID 6, TID 6, PC echo+0x8) second event BPT(VID 10, TID 10, PC echo+0x8) the following handlers will miss events:

在这些情况下,如果可以确定条件表达式中调用的函数不会抓取互斥锁,则可使用 -resumeone 事件修饰符强制 dbx 只恢复 t@1:

stop in lookup -resumeone -if strcmp(name, "troublesome") == 0

只恢复在 lookup() 中遇到断点的线程,以便对 strcmp() 进行求值。

此方法在诸如以下的情况下会无能为力:

由于条件以递归方式调用 lookup(),lookup() 上的第二个断点发生在同一个线程中

运行条件的线程放弃控制权、休眠或以某种方式将控制权交给另一个线程

了解线程创建活动

通过使用以下示例中的 thr_create 事件和 thr_exit 事件,可以了解应用程序创建和销毁线程的频率:

(dbx) trace thr_create

(dbx) trace thr_exit

(dbx) run

trace: thread created t@2 on l@2

trace: thread created t@3 on l@3

trace: thread created t@4 on l@4

trace: thr_exit t@4

trace: thr_exit t@3

trace: thr_exit t@2

该应用程序创建了三个线程。请注意线程是如何以相反顺序从其创建中退出来的。这可能表明,如果此应用程序中的线程偏多,就会导致线程累积并消耗资源。

要获得更多值得注意的信息,可以在不同会话中尝试以下操作:

(dbx) when thr_create { echo "XXX thread $newthread created by $thread"; }

XXX thread t@2 created by t@1

XXX thread t@3 created by t@1

XXX thread t@4 created by t@1

此输出显示三个线程全部是由公用多线程模式的 t@1 线程创建的。

假设您要从开头调试线程 t@3。可以在线程 t@3 创建为如下所示时停止应用程序。

(dbx) stop thr_create t@3

(dbx) run

t@1 (l@1) stopped in tdb_event_create at 0xff38409c

0xff38409c: tdb_event_create : retl

Current function is main

216 stat = (int) thr_create(NULL, 0, consumer, q, tflags, &tid_cons2);

(dbx)

如果您的应用程序有时从线程 t@5 而不是从线程 t@1 产生新的线程,则可以按如下所示捕获此事件:

(dbx) stop thr_create -thread t@5

理解 LWP 信息

通常无需注意 LWP。但有时无法完成线程级查询。在这些情况下,使用 lwps 命令来显示有关 LWP 的信息。

(dbx) lwps

l@1 running in main()

l@2 running in sigwait()

l@3 running in _lwp_sema_wait()

*>l@4 breakpoint in Queue_dequeue()

l@5 running in _thread_start()

(dbx)

LWP 列表的每行都包含下列内容:

*(星号)表示此 LWP 内发生了需要用户处理的事件。

箭头表示为当前 LWP。

l@number 指特定 LWP。

下一项代表 LWP 状态。

在 function_name() 中标识 LWP 当前正在执行的函数。

使用lwp 命令列出或更改当前的 LWP。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值