[ 永遠的UNIX::UNIX技術資料的寶庫 ]   GB | BIG5

首頁 > 編程技術 > C/C++ > 正文
Solaris2.4 多線程編程指南6--編譯和調試
本文出自:BBS水木清華站 作者:Mccartney (coolcat) (2002-01-29 20:32:52)
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. (http://www.fanqiang.com)
    進入【UNIX論壇

相關文章
Solaris2.4 多線程編程指南7--編程指南 (2002-01-29 20:33:46)
Solaris2.4 多線程編程指南6--編譯和調試 (2002-01-29 20:32:52)
Solaris2.4 多線程編程指南5--安全和不安全的接口函數 (2002-01-29 20:32:05)
Solaris2.4 多線程編程指南4--操作系統編程 (2002-01-29 20:29:36)
Solaris2.4 多線程編程指南3--使用同步對象編程 (2002-01-29 20:28:07)
Solaris2.4 多線程編程指南2--用多線程編程 (2002-01-29 20:26:32)
Solaris2.4 多線程編程指南1--線程基礎 (2002-01-29 20:25:25)
Linux下的多線程編程 (2001-08-11 09:05:00)
 

★  樊強制作 歡迎分享  ★