以下列表指出了在多线程程序中可能导致错误的一些经常被疏忽的问题。
两个线程尝试轮流获取对同一对全局资源的权限时导致死锁。 其中一个线程控制第一种资源,另一个线程控制第二种资源。其中一个线程放弃之前,任何一个线程都无法继续操作。
在同步保护中创建隐藏的间隔。 如果受保护的代码段包含的函数释放了同步机制,而又在返回调用方之前重新获取了该同步机制,则将在保护中出现此间隔。结果具有误导性。对于调用方,表面上看全局数据已受到保护,而实际上未受到保护。
忘记已创建缺省线程 PTHREAD_CREATE_JOINABLE 并且必须使用 pthread_join(3C) 来进行回收。请注意,pthread_exit(3C) 不会释放其存储空间。
多线程程序(特别是那些包含错误的程序)经常在两次连续运行中的行为方式不同,即使输入相同也是如此。此行为是由线程调度顺序的差异所导致的。
一般情况下,多线程错误是统计得出的,不具有确定性。通常,与基于断点的调试相比,跟踪是用于查找执行顺序问题的一种更有效的方法。
请使用 TNF 实用程序跟踪、调试和收集应用程序和库中的性能分析信息。TNF 实用程序将内核以及多个用户进程和线程中的跟踪信息整合在一起。TNF 实用程序对于多线程代码特别有用。TNF 实用程序包括在 Solaris 软件中,是该软件的一部分。
使用 TNF 实用程序,可以轻松跟踪和调试多线程程序。有关使用 prex(1) 和 tnfdump(1) 的详细信息,请参见 TNF 手册页。
有关跟踪系统调用、信号和用户级别函数调用的信息,请参见 truss(1) 手册页。
有关 mdb 的信息,请参见《Solaris Modular Debugger Guide》。
如果目标为用户进程,则将列显有代表性的线程的 LWP ID。
如果目标为用户进程,则将列显目标中每个 LWP 的 LWP ID。
附加到编号为 pid 的进程。
释放以前附加的进程或核心转储文件。随后可以由 prun(1) 继续处理进程,或者可通过应用 MDB 或其他调试器来恢复进程。
上下文切换到指定进程。
这些用于设置条件断点的命令通常很有用。
在指定的位置设置断点。
删除包含给定 ID 编号的事件说明符。
使用 dbx 实用程序,可以调试和执行使用 C++、ANSI C 和 FORTRAN 编写的源代码程序。dbx 与调试器接受同样的命令,但使用标准的终端 (TTY) 接口。dbx 和调试器都支持调试多线程程序。有关如何启动 dbx 的说明,请参见 dbx(1) 手册页。有关 dbx 的概述,请参见《Debugging a Program With dbx》。调试器功能在 dbx 的调试器 GUI 的联机帮助中介绍。
表 7–2 中列出的所有 dbx 选项均可支持多线程应用程序。
表 7–2 MT 程序的 dbx 选项
选项 |
操作 |
---|---|
cont at line [-sig signo id] |
在包含信号 signo 的 line 中继续执行操作。id(如果存在)指定哪个线程或 LWP 继续操作。缺省值为 all。 |
lwp |
显示当前的 LWP。切换到给定 LWP [lwpid]。 |
lwps |
列出当前进程中所有的 LWP。 |
next ... tid |
单步执行给定线程。跳过函数调用时,所有的 LWP 都会在该函数调用期间隐式恢复。不能单步执行非活动线程。 |
next ... lid |
单步执行给定 LWP。跳过函数时不会隐式恢复所有 LWP。所含的给定线程处于活动状态的 LWP。跳过函数时不会隐式恢复所有 LWP。 |
step... tid |
单步执行给定线程。跳过函数调用时,所有的 LWP 都会在该函数调用期间隐式恢复。不能单步执行非活动线程。 |
step... lid |
单步执行给定 LWP。跳过函数时不会隐式恢复所有 LWP。 |
stepi... lid |
给定的 LWP。 |
stepi... tid |
所含的给定线程处于活动状态的 LWP。 |
thread |
显示当前线程。切换到线程 tid。在下面所有的变体中,可选的 tid 表示当前线程。 |
thread -info [ tid ] |
列显有关给定线程的所有已知信息。 |
thread -blocks [ tid ] |
列显阻塞其他线程的给定线程持有的所有锁定。 |
thread -suspend [ tid ] |
使给定线程进入暂停状态。 |
thread -resume [ tid ] |
取消暂停给定线程。 |
thread -hide [ tid ] |
隐藏给定线程或当前线程。该线程不会出现在通用的 threads 列表中。 |
thread -unhide [ tid ] |
取消隐藏给定线程或当前线程。 |
thread -unhide all |
取消隐藏所有线程。 |
threads |
列显所有已知线程的列表。 |
threads -all |
列显通常不会列显的线程(僵线程)。 |
threads -mode all|filter |
控制在缺省情况下,threads 是列显所有线程,还是过滤线程。 |
threads -mode auto|manual |
实现线程列表的自动更新。 |
threads -mode |