下列步骤说明了使用线程分析器为多线程程序排除故障的过程。
检测程序(如果进行数据争用检测)。
创建数据争用检测实验或死锁检测实验。
检查实验结果,并确定线程分析器所发现的多线程编程问题属于真实错误还是良性现象。
修复真实的错误,并使用不同的因素(如不同的输入数据、不同的线程数、不同的循环调度,乃至不同的硬件)创建其他实验(上面的步骤 2)。这种重复有助于找出原因不确定的问题。
以下几节将介绍上述的步骤 1 到步骤 3。
必须执行下列三个步骤来检测数据争用:
检测代码以允许数据争用检测
基于检测后的代码创建实验
检查实验中是否存在数据争用
要在应用程序中启用数据争用检测,必须首先检测代码来监视运行时内存访问,表示必须在代码中插入对运行时支持库 libtha.so 的调用以便监视运行时内存访问并确定是否存在任何数据争用。
可以在编译过程中在应用程序源代码级别检测代码,也可以通过对二进制代码运行其他工具在应用程序二进制代码级别检测代码。
源代码级别检测通过编译器完成,需要使用特殊选项。还可以指定优化级别以及要使用的其他编译器选项。由于编译器可以进行一些分析工作并检测较少的内存访问,因此源代码级别检测可使运行时速度更快。
源代码不可用时,可以使用二进制代码级别检测。有源代码时也可以使用二进制代码检测,但无法编译应用程序所使用的共享库。如果使用 discover 工具进行二进制代码检测,则可以检测二进制代码并可在所有共享库打开时检测所有这些共享库。
要在源代码级别进行检测,请使用特殊的编译器选项编译源代码:
-xinstrument=datarace
通过使用该编译器选项,将会对编译器生成的代码进行检测以便检测数据争用。
生成应用程序二进制代码时,还应使用 –g 编译器选项。该选项会导致生成额外数据,线程分析器通过该数据可以在报告数据争用时显示源代码和行号信息。
要在二进制代码级别进行检测,必须使用 discover 工具。如果二进制代码命名为 a.out,可以通过执行以下命令创建检测后的二进制代码 a.outi:
discover -i datarace -o a.outi a.out
discover 工具在所有共享库打开时自动检测所有这些共享库(无论它们是静态链接到程序中的,还是通过 dlopen() 动态打开的)。缺省情况下,检测后的库副本会缓存到 $HOME/SUNW_Bit_Cache 目录中。
下面显示了一些有用的 discover 命令行选项。有关详细信息,请参见 discover(1) 手册页。
将检测后的二进制代码输出到指定文件名
不检测指定的库
不检测任何库
将高速缓存目录更改为 dir
要创建数据争用检测实验,请使用带有 –r race 标志的 collect 命令运行应用程序并在进程执行期间收集实验数据。使用 –r race 选项时,收集到的数据包含构成争用的数据访问对。
可以使用 tha 命令检查数据争用检测实验,该命令会启动线程分析器图形用户界面。也可以使用 er_print 命令行界面。
检测死锁包括两个步骤:
创建死锁检测实验。
检查实验中是否存在死锁。
要创建死锁检测实验,请使用带有 –r deadlock 标志的 collect 命令运行应用程序并在进程执行期间收集实验数据。使用 –r deadlock 选项时,收集到的数据包含形成循环链的锁持有和锁请求。
可以使用 tha 命令检查死锁检测实验,该命令会启动线程分析器图形用户界面。也可以使用 er_print 命令行界面。
如果要同时检测数据争用和死锁,请按照检测数据争用的使用模型中的三个步骤来检测数据争用,但要使用带有 r race,deadlock 标志的 –collect 命令来运行应用程序。实验将同时包含争用检测数据和死锁检测数据。