发信人: tcpip (俺的昵称改了), 信区: cnunix
标  题: Solaris多线程编程指南6--编译和调试
发信站: 哈工大紫丁香 (Sun Sep 26 15:16:00 1999), 转信

寄信人: NTMD.bbs@bbs.net.tsinghua.edu.cn 
发信站: 华南理工大学 BBS木棉站
日  期: Wed Aug  5 18:34:01 1998

发信人: Mccartney (coolcat), 信区: Unix
标  题: Solaris多线程编程指南6--编译和调试
发信站: BBS 水木清华站 (Sun May 17 16:33:41 1998)

6 编译和调试

    本章描述了怎样编译和调试多线程程序。
        编译一个多线程应用程序
        调试一个多线程应用程序

6.1编译一个多线程应用程序

6.1.1使用C编译器

    确认你拥有如下软件,否则将无法正常编译和连接多线程程序
        · 头文件:thread.h errno.h
        · 标准C编译器
        · 标准Solaris连接器
        · 线程库(libthread)
        · MT-Safe库(libc, libm, libw, libintl, libmalloc, 
                libmapmalloc, libnsl, 等等)

6.1.2用替代(_REENTRANT)标志进行编译

    在编译多线程程序时使用"-D _REENTRANT"标志。
    这个标志必须在编译应用程序的每一个模块时都使用。如果没有这个标志,将
使用errno, stdio等等的旧的定义。如果要编译一个单线程应用程序,不要使用这
个标志。

*新旧连接需要小心

    表6-1显示了多线程目标代码模块与旧的代码模块连接时需要非常慎重。
        表6-1 在编译多线程程序时使用"-D _REENTRANT"标志
文件类型                编译            参考            返回
旧的目标文件(非线程版)和新的目标文件  没有 "-D _REENTRANT" 标志。     静态储存        传统的errno
新的目标文件    有 "-D _REENTRANT"标志。        __errno,新的二进制入口 线程定义errno的地址
用libnsl 里的TLI编程    有 "-D _REENTRANT"标志(必须)。        __t_errno,一个新的入口 线程定义t_errno的地址

6.1.3使用libthread

    为了在连接时使用libthread,需要在ld命令行里,-lc参数之前,指定
-lthread,或者在cc 命令行的最后指定。
    如果应用程序没有连接libthread,则对该库中的函数调用不产生实际操作。
    Libc定义libthread为空过程。???真正的过程是在应用程序既连接libc也
连接libthread时由libthread加入的。
    如果一个ld命令行包含了以下的字段:.o's ... -lc -lthread ...,则C函数
库的行为没有被定义。???
    不要在单线程程序中使用-lthread。这样做将在连接时建立多线程机制,在运
行时将被初始化。这样做不但浪费资源,而且在调试中会对运行结果有不正确的显示。

6.1.4使用非C的编译器

    线程库使用libc中的如下内容:
· 系统调用包装器(system call wrappers)
· 用来显示出错信息的调用(通常是printf)
· 运行时的连接支持来解析符号(因为库是动态连接的)

    你也可以写自己的系统调用包装器和自己的printf函数,并且在连接时(而不
是在运行时)进行符号解析,这样可以消除对libc的依赖。
    如果线程使用应用程序提供的堆栈,则线程库不使用动态分配内存的办法。
Thr_create(3T)函数可以由应用程序指定自己的堆栈。

6.2调试多线程应用程序

6.2.1一般的疏漏
        以下列出可以导致多线程出错的常见疏漏:
· 给新线程传递参数时使用局部或全局变量
· 在没有同步机制的保护下访问全局内存
· 两个线程以不同的顺序去申请两个资源导致死锁(两个线程各自占有一个资源
并相执不下)
· 在同步保护中有隐藏的漏洞。例如可能有如下情况:一个有同步机制(例如互斥
锁)保护的代码段包含一个先释放再重新获得同步机制的函数调用,结果是全局内存
实际上没有得到保护。
· 有隐匿的,重复或递归的大自动数组的使用可能导致问题,因为多线程程序的堆
栈容量比单线程程序有更多的限制。
· 指定的堆栈空间不够。
· 没有通过线程库的调用指定堆栈。
    注意,多线程程序(特别是有错误的)经常在相同输入的情况下得到不同的结
果,因为线程调度的顺序不同。
    一般的,多线程bug具有统计性,而不是确定性。在调试时,跟踪的办法将会比
设断点的办法好些。

6.2.2使用adb

    如果你在一个多线程程序当中绑定所有线程,一个线程和一个LWP是同步的。然
后你通过如下支持多线程编程的adb命令访问每一个线程。

表6-2 MT adb命令
-------------------------------------
pid:A                   绑定在进程pid上,这将停止进程及其所有LWP
:R                      与进程分离,这将恢复进程及其所有LWP
$L                      显示在(停止的)进程中所有的活动的LWP
n:l                     将焦点切换到第n号LWP
$l                      显示当前焦点所在的LWP
num:i                   忽略信号码为num的信号

6.2.3使用dbx

    使用dbx,可以调试和执行用C++, ANSI C, FORTRAN和PASCAL的源程序。Dbx使
用与SPARCworks? Debugger相同的命令,但使用标准终端(tty)接口。Dbx和
SPARCworks Debugger现在都支持多线程程序。
    要得到dbx和Debugger的全面认识,请参考SunPro dbx(1) man page和
《Debugging a Program》用户指南。
    以下的dbx选项支持多线程。
        表6-3 给MT程序使用的dbx选项
Cont at line[sig signo id]      在信号signo发生时继续执行第line行。
                                参见dbx的命令语言的循环控制里的continue。
                                如果有id参数,则指定继续哪一个线程或LWP。
                                缺省设置为all。
Lwp                             显示当前LWP。切换到给定LWP[lwpid]
Lwps                            列出当前进程的所有LWP
Next … tid                     单步执行指定线程。如果一个函数调用被跳过,
                                所有的LWP在该函数调用期间重新开始???非
                                活动线程不能被单步执行
Next … lid                     单步执行指定LWP。在跳过函数时并不隐含地恢
                                复所有的LWP。在该LWP上的线程是活动的。
Step … tid                     单步执行指定线程。如果一个函数调用被跳过,
                                所有的LWP在该函数调用期间重新开始???非
                                活动线程不能被单步执行
Step … lid                     单步执行指定LWP。在跳过函数时并不隐含地恢
                                复所有的LWP。
Stepi … lid                    指定的LWP
Stepi … tid                    在LWP上的线程是活动的。
Thread                          显示当前线程。切换到线程tid。在以下情况中,
                                一个可选的tid指当前线程。
Thread -info[tid]               打印指定线程的所有已知情况。
Thread -locks[tid]              打印被指定线程控制的所有锁
Thread -suspend[tid]            把指定线程置于挂起状态。
Thread -continue[tid]           使指定线程退出挂起状态。
Thread -hide[tid]               隐藏指定(或当前)线程,在普通线程列表中
                                将不被显示出来
Thread -unhide [tid]            解除指定线程的隐藏状态
Allthread-unhide                解除所有线程的隐藏状态
Threads                         打印已知线程的列表
Threads-all                     打印所有线程(包括通常不被打印的,zombies)
All|filterthreads-mode          控制threads命令打印所有线程还是有选择地列表
Auto|manualthreads-mode         使在GUI界面里线程监控器(Thread Inspector)
                                线程列表得以自动更新
Threads -mode                   显示当前模式。Any of the previous forms 
                                can be followed by a
thread or LWP ID to get the traceback for the specified entity.

--
※ 修改:.trueip 于 Sep 26 15:19:46 修改本文.[FROM: dns.mtlab.hit.ed]
--
※ 转寄:.华南网木棉站 bbs.gznet.edu.cn.[FROM: dns.mtlab.hit.ed]

--
☆ 来源:.哈工大紫丁香 bbs.hit.edu.cn.[FROM: trueip.bbs@melon.gzn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:3.445毫秒