• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            elva

            GDB(GNU 項(xiàng)目調(diào)試器)

            GDB(GNU 項(xiàng)目調(diào)試器)可以讓您了解程序在執(zhí)行時“內(nèi)部” 究竟在干些什么,以及在程序發(fā)生崩潰的瞬間正在做什么。
            GDB 做以下 4 件主要的事情來幫助您捕獲程序中的 bug:
            l
            在程序啟動之前指定一些可以影響程序行為的變量或條件
            l
            在某個指定的地方或條件下暫停程序
            l
            在程序停止時檢查已經(jīng)發(fā)生了什么
            l
            在程序執(zhí)行過程中修改程序中的變量或條件,這樣就可以體驗(yàn)修復(fù)一個 bug 的成果,并繼續(xù)了解其他 bug

            要調(diào)試的程序可以是使用 C、C++、Pascal、Objective-C 以及其他很多語言編寫的。GDB 的二進(jìn)制文件名是 gdb。
            gdb 中有很多命令。使用help命令可以列出所有的命令,以及關(guān)于如何使用這些命令的介紹。下表給出了最常用的 GDB 命令。

            表 1. gdb 中最常用的命令
            命令
            說明
            例子
            help
            顯示命令類別
            help- 顯示命令類別
            help breakpoints- 顯示屬于 breakpoints 類別的命令
            help break- 顯示 break 命令的解釋
            run
            啟動所調(diào)試的程序
            ?
            kill
            終止正在調(diào)試的程序的執(zhí)行
            通常這會在要執(zhí)行的代碼行已經(jīng)超過了您想要調(diào)試的代碼時使用。執(zhí)行kill會重置斷點(diǎn),并從頭再次運(yùn)行這個程序



            cont
            所調(diào)試的程序運(yùn)行到一個斷點(diǎn)、異?;騿尾街螅^續(xù)執(zhí)行
            ?
            info break
            顯示當(dāng)前的斷點(diǎn)或觀察點(diǎn)
            ?
            break
            在指定的行或函數(shù)處設(shè)置斷點(diǎn)
            break 93 if i=8- 當(dāng)變量 i 等于 8 時,在第 93 行停止程序執(zhí)行
            Step
            單步執(zhí)行程序,直到它到達(dá)一個不同的源代碼行。您可以使用s來代表 step 命令
            ?
            Next
            與 step 命令類似,只是它不會“單步跟蹤到”子例程中
            ?
            print
            打印一個變量或表達(dá)式的值
            print pointer- 打印變量指針的內(nèi)容
            print *pointer- 打印指針?biāo)赶虻臄?shù)據(jù)結(jié)構(gòu)的內(nèi)容
            delete
            刪除某些斷點(diǎn)或自動顯示表達(dá)式
            delete 1- 刪除斷點(diǎn) 1。斷點(diǎn)可以通過info break來顯示
            watch
            為一個表達(dá)式設(shè)置一個觀察點(diǎn)。當(dāng)表達(dá)式的值發(fā)生變化時,這個觀察點(diǎn)就會暫停程序的執(zhí)行
            ?
            where
            打印所有堆棧幀的棧信息
            where- 不使用參數(shù),輸出當(dāng)前線程的堆棧信息
            where all- 輸出當(dāng)前線程組中所有線程的堆棧信息
            where threadindex- 輸出指定線程的堆棧信息
            attach
            開始查看一個已經(jīng)運(yùn)行的進(jìn)程
            attach - 附加到進(jìn)程 process_id 上。process_id 可以使用 ps 命令找到
            info thread
            顯示當(dāng)前正在運(yùn)行的線程
            ?
            thread apply threadno command
            對一個線程運(yùn)行 gdb 命令
            thread apply 3 where- 對線程 3 運(yùn)行where命令
            Thread threadno
            選擇一個線程作為當(dāng)前線程
            ?
            如果一個程序崩潰了,并生成了一個 core 文件,您可以查看 core 文件來判斷進(jìn)程結(jié)束時的狀態(tài)。使用下面的命令啟動 gdb:
            # gdb programname corefilename
            要調(diào)試一個 core 文件,您需要可執(zhí)行程序、源代碼文件以及 core 文件。要對一個 core 文件啟動 gdb,請使用 -c 選項(xiàng):
            # gdb -c core programname
            gdb 會顯示是哪行代碼導(dǎo)致這個程序產(chǎn)生了核心轉(zhuǎn)儲。
            默認(rèn)情況下,核心轉(zhuǎn)儲在 Novell 的 SUSE LINUX Enterprise Server 9(SLES 9)和 Red Hat? Enterprise Linux Advanced Server(RHEL AS 4)上都是禁用的。要啟用核心轉(zhuǎn)儲,請以 root 用戶的身份在命令行中執(zhí)行ulimit –c unlimited。
            清單 8中的例子闡述了如何使用 gdb 來定位程序中的 bug。清單 8 是一段包含 bug 的 C++ 代碼。
            清單 8中的 C++ 程序試圖構(gòu)建 10 個鏈接在一起的數(shù)字框(number box),例如:

            圖 1. 一個包含 10 個鏈接在一起的數(shù)字框的列表

            然后試圖從這個列表中逐個刪除數(shù)字框。
            編譯并運(yùn)行這個程序,如下所示:

            清單 9. 編譯并運(yùn)行這個程序
            # g++ -g -o gdbtest1 gdbtest1.cpp
            # ./gdbtest1
            Number Box "0" created
            Number Box "1" created
            Number Box "2" created
            Number Box "3" created
            Number Box "4" created
            Number Box "5" created
            Number Box "6" created
            Number Box "7" created
            Number Box "8" created
            Number Box "9" created
            list created
            Number Box "9" deleted
            Segmentation fault
            正如您可以看到的一樣,這個程序會導(dǎo)致段錯誤。調(diào)用 gdb 來看一下這個問題,如下所示:

            清單 10. 調(diào)用 gdb
            # gdb ./gdbtest1
            GNU gdb 6.2.1
            Copyright 2004 Free Software Foundation, Inc.
            GDB is free software, covered by the GNU General Public License, and you
            are welcome to change it and/or distribute copies of it under certain
            conditions.
            Type "show copying" to see the conditions.
            There is absolutely no warranty for GDB.
            Type "show warranty" for
            details.
            This GDB was configured as "ppc-suse-linux"...Using host libthread_db
            library "/lib/tls/libthread_db.so.1".
            (gdb)
            您知道段錯誤是在數(shù)字框 "9" 被刪除之后發(fā)生的。執(zhí)行run和where命令來精確定位段錯誤發(fā)生在程序中的什么位置。

            清單 11. 執(zhí)行 run 和 where 命令
            (gdb) run
            Starting program: /root/test/gdbtest1
            Number Box "0" created
            Number Box "1" created
            Number Box "2" created
            Number Box "3" created
            Number Box "4" created
            Number Box "5" created
            Number Box "6" created
            Number Box "7" created
            Number Box "8" created
            Number Box "9" created
            list created
            Number Box "9" deleted
            Program received signal SIGSEGV, Segmentation fault.
            0x10000f74 in NumBox::GetNext (this=0x0) at gdbtest1.cpp:14
            14
            NumBox*GetNext() const { return Next; }
            (gdb) where
            #0
            0x10000f74 in NumBox::GetNext (this=0x0) at gdbtest1.cpp:14
            #1
            0x10000d10 in NumChain::RemoveBox (this=0x10012008,
            item_to_remove=@0xffffe200) at gdbtest1.cpp:63
            #2
            0x10000978 in main (argc=1, argv=0xffffe554) at gdbtest1.cpp:94
            (gdb)
            跟蹤信息顯示這個程序在第 14 行NumBox::GetNext (this=0x0)接收到一個段錯誤。這個數(shù)字框上 Next 指針的地址是 0x0,這對于一個數(shù)字框來說是一個無效的地址。從上面的跟蹤信息可以看出,GetNext函數(shù)是由 63 行調(diào)用的。看一下在 gdbtest1.cpp 的 63 行附近發(fā)生了什么:

            清單 12. gdbtest1.cpp
            54
            } else {

            55
            temp->SetNext (current->GetNext());

            56
            delete temp;

            57

            temp = 0;

            58
            return 0;

            59
            }

            60
            }

            61
            current = 0;

            62
            temp = current;

            63
            current = current->GetNext();

            64
            }

            65

            66
            return -1;
            第 61 行current=0將這個指針設(shè)置為一個無效的地址,這正是產(chǎn)生段錯誤的根源。注釋掉第 61 行,將其保存為 gdbtest2.cpp,然后編譯并重新運(yùn)行。

            清單 13. 再次運(yùn)行程序(gdbtest2.cpp)
            # g++ -g -o gdbtest2 gdbtest2.cpp
            # ./gdbtest2
            Number Box "0" created
            Number Box "1" created
            Number Box "2" created
            Number Box "3" created
            Number Box "4" created
            Number Box "5" created
            Number Box "6" created
            Number Box "7" created
            Number Box "8" created
            Number Box "9" created
            list created
            Number Box "9" deleted
            Number Box "0" deleted
            這個程序現(xiàn)在可以成功完成而不會出現(xiàn)段錯誤了。然而,結(jié)果并不像我們預(yù)期的一樣:程序在刪除 Number Box "9"之后刪除了 Number Box "0",而不像我們期望的一樣刪除 Number Box "8,"。使用 gdb 再次來看一下。

            清單 14. 再次使用 gdb 進(jìn)行查看
            # gdb ./gdbtest2
            GNU gdb 6.2.1
            Copyright 2004 Free Software Foundation, Inc.
            GDB is free software, covered by the GNU General Public License, and you
            are welcome to change it and/or distribute copies of it under certain
            conditions.
            Type "show copying" to see the conditions.
            There is absolutely no warranty for GDB.
            Type "show warranty" for
            details.
            This GDB was configured as "ppc-suse-linux"...Using host libthread_db
            library "/lib/tls/libthread_db.so.1".
            (gdb) break 94 if i==8
            Breakpoint 1 at 0x10000968: file gdbtest2.cpp, line 94.
            (gdb) run
            Starting program: /root/test/gdbtest2
            Number Box "0" created
            Number Box "1" created
            Number Box "2" created
            Number Box "3" created
            Number Box "4" created
            Number Box "5" created
            Number Box "6" created
            Number Box "7" created
            Number Box "8" created
            Number Box "9" created
            list created
            Number Box "9" deleted
            Breakpoint 1, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94
            94
            list ->RemoveBox(i);
            您可能希望找出為什么這個程序刪除的是 Number Box 0,而不是 Number Box 8,因此需要在您認(rèn)為程序會刪除 Number Box 8 的地方停止程序。設(shè)置這個斷點(diǎn):break 94 if i==8,可以在 i 等于 8 時在第 94 行處停止程序。然后單步跟蹤到RemoveBox()函數(shù)中。

            清單 15. 單步跟蹤到 RemoveBox() 函數(shù)中
            (gdb) s
            38
            NumBox *temp = 0;

            (gdb) s
            40
            while (current != 0) {
            (gdb) print pointer
            $1 = (NumBox *) 0x100120a8

            (gdb) print *pointer
            $2 = {Num = 0, Next = 0x0}
            (gdb)
            指針早已指向了 Number Box "0",因此這個 bug 可能就存在于程序刪除 Number Box "9" 的地方。要在 gdb 中重新啟動這個程序,請使用kill刪除原來的斷點(diǎn),然后添加一個 i 等于 9 時的新斷點(diǎn),然后再次運(yùn)行這個程序。

            清單 16. 在 gdb 中重新啟動程序
            (gdb) kill
            Kill the program being debugged? (y or n) y
            (gdb) info break
            Num Type
            Disp Enb Address
            What
            1
            breakpoint
            keep y
            0x10000968 in main at gdbtest2.cpp:94

            stop only if i == 8

            breakpoint already hit 1 time
            (gdb) delete 1
            (gdb) break 94 if i==9
            Breakpoint 2 at 0x10000968: file gdbtest2.cpp, line 94.
            (gdb) run
            Starting program: /root/test/gdbtest2
            Number Box "0" created
            Number Box "1" created
            Number Box "2" created
            Number Box "3" created
            Number Box "4" created
            Number Box "5" created
            Number Box "6" created
            Number Box "7" created
            Number Box "8" created
            Number Box "9" created
            list created
            Breakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94
            94
            list ->RemoveBox(i);
            (gdb)
            當(dāng)這一次單步跟蹤RemoveBox()函數(shù)時,要特別注意list->pointer正在指向哪一個數(shù)字框,因?yàn)?bug 可能就在于list->pointer開始指向 Number Box "0" 的地方。請使用display *pointer命令來查看,這會自動顯示這個函數(shù)。

            清單 17. 使用 display *pointer 命令進(jìn)行監(jiān)視
            Breakpoint 2, main (argc=1, argv=0xffffe554) at gdbtest2.cpp:94
            94
            list ->RemoveBox(i);
            (gdb) s
            NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
            at gdbtest2.cpp:37
            37
            NumBox *current = pointer;
            (gdb) display *pointer
            1: *this->pointer = {Num = 9, Next = 0x10012098}
            (gdb) s
            38
            NumBox *temp = 0;

            1: *this->pointer = {Num = 9, Next = 0x10012098}
            (gdb) s
            40
            while (current != 0) {
            1: *this->pointer = {Num = 9, Next = 0x10012098}
            (gdb) s
            41
            if (current->GetValue() == item_to_remove) {
            1: *this->pointer = {Num = 9, Next = 0x10012098}
            (gdb) s
            NumBox::GetValue (this=0x100120a8) at gdbtest2.cpp:16
            16
            const T& GetValue () const { return Num; }
            (gdb) s
            NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
            at gdbtest2.cpp:42
            42
            if (temp == 0) {
            1: *this->pointer = {Num = 9, Next = 0x10012098}
            (gdb) s
            44
            if (current->GetNext() == 0) {
            1: *this->pointer = {Num = 9, Next = 0x10012098}
            (gdb) s
            NumBox::GetNext (this=0x100120a8) at gdbtest2.cpp:14
            14
            NumBox*GetNext() const { return Next; }
            (gdb) s
            NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
            at gdbtest2.cpp:50
            50
            delete current;
            1: *this->pointer = {Num = 9, Next = 0x10012098}
            (gdb) s
            ~NumBox (this=0x100120a8) at gdbtest2.cpp:10
            10
            std::cout << "Number Box " <<"\""
            << GetValue()
            <<"\""
            <<" deleted" << std::endl;
            (gdb) s
            NumBox::GetValue (this=0x100120a8) at gdbtest2.cpp:16
            16
            const T& GetValue () const { return Num; }
            (gdb) s
            Number Box "9" deleted
            ~NumBox (this=0x100120a8) at gdbtest2.cpp:11
            11
            Next = 0;
            (gdb) s
            NumChain::RemoveBox (this=0x10012008, item_to_remove=@0xffffe200)
            at gdbtest2.cpp:51
            51
            current = 0;
            1: *this->pointer = {Num = 0, Next = 0x0}
            (gdb) s
            53
            return 0;
            1: *this->pointer = {Num = 0, Next = 0x0}
            (gdb) s
            0x10000d1c
            66
            return -1;
            1: *this->pointer = {Num = 0, Next = 0x0}
            從上面的跟蹤過程中,您可以看到list->pointer在刪除 Number Box "9" 之后指向了 Number Box "0"。這個邏輯并不正確,因?yàn)樵趧h除 Number Box "9" 之后,list->pointer應(yīng)該指向的是 Number Box "8"?,F(xiàn)在非常顯然我們應(yīng)該在第 50 行之前添加一條語句pointer = pointer->GetNext();,如下所示:

            清單 18. 在第 50 行之前添加一條 pointer = pointer->GetNext(); 語句
            49
            } else {

            50
            pointer = pointer->GetNext();

            51
            delete current;

            52
            current = 0;

            53
            }

            54

            return 0;
            將新修改之后的程序保存為 gdbtest3.cpp,然后編譯并再次運(yùn)行。

            清單 19. 再次運(yùn)行程序(gdbtest3.cpp)
            # g++ -g -o gdbtest3 gdbtest3.cpp
            # ./gdbtest3
            Number Box "0" created
            Number Box "1" created
            Number Box "2" created
            Number Box "3" created
            Number Box "4" created
            Number Box "5" created
            Number Box "6" created
            Number Box "7" created
            Number Box "8" created
            Number Box "9" created
            list created
            Number Box "9" deleted
            Number Box "8" deleted
            Number Box "7" deleted
            Number Box "6" deleted
            Number Box "5" deleted
            Number Box "4" deleted
            Number Box "3" deleted
            Number Box "2" deleted
            Number Box "1" deleted
            Number Box "0" deleted
            這才是我們期望的結(jié)果。
            多線程環(huán)境
            在 GDB 中有一些特殊的命令可以用于多線程應(yīng)用程序的調(diào)試。下面這個例子給出了一個死鎖情況,并介紹了如何使用這些命令來檢查多線程應(yīng)用程序中的問題:

            清單 20. 多線程的例子
            #include
            #include "pthread.h>
            pthread_mutex_t AccountA_mutex;
            pthread_mutex_t AccountB_mutex;
            struct BankAccount {

            char account_name[1];

            int balance;
            };
            struct BankAccount
            accountA = {"A", 10000 };
            struct BankAccount
            accountB = {"B", 20000 };
            void * transferAB (void* amount_ptr) {

            int amount = *((int*)amount_ptr);

            pthread_mutex_lock(&AccountA_mutex);

            if (accountA.balance < amount)
            {

            printf("There is not enough memory in Account A!\n");

            pthread_mutex_unlock(&AccountA_mutex);


            pthread_exit((void *)1);

            }

            accountA.balance -=amount;

            sleep(1);

            pthread_mutex_lock(&AccountB_mutex);

            accountB.balance +=amount;

            pthread_mutex_unlock(&AccountA_mutex);

            pthread_mutex_unlock(&AccountB_mutex);
            }
            void * transferBA (void* amount_ptr) {

            int amount = *((int*)amount_ptr);

            pthread_mutex_lock(&AccountB_mutex);

            if (accountB.balance < amount)
            {

            printf("There is not enough memory in Account B!\n");

            pthread_mutex_unlock(&AccountB_mutex);

            pthread_exit((void *)1);

            }

            accountB.balance -=amount;

            sleep(1);

            pthread_mutex_lock(&AccountA_mutex);

            accountA.balance +=amount;

            pthread_mutex_unlock(&AccountB_mutex);

            pthread_mutex_unlock(&AccountA_mutex);
            }
            int main(int argc, char* argv[]) {

            int
            threadid[4];

            pthread_t
            pthread[4];

            int
            transfer_amount[4] = {100, 200, 300, 400};

            int
            final_balanceA, final_balanceB;

            final_balanceA=accountA.balance-transfer_amount[0]-
            transfer_amount[1]+transfer_amount[2]+transfer_amount[3];

            final_balanceB=accountB.balance+transfer_amount[0]
            +transfer_amount[1]-transfer_amount[2]-transfer_amount[3];

            if (threadid[0] = pthread_create(&pthread[0], NULL, transferAB,
            (void*)&transfer_amount[0]) " 0) {

            perror("Thread #0 creation failed.");

            exit (1);

            }

            if (threadid[1] = pthread_create(&pthread[1], NULL, transferAB,
            (void*)&transfer_amount[1]) " 0) {

            perror("Thread #1 creation failed.");

            exit (1);

            }

            if (threadid[2] = pthread_create(&pthread[2], NULL, transferBA,
            (void*)&transfer_amount[2]) < 0) {

            perror("Thread #2 creation failed.");

            exit (1);

            }

            if (threadid[3] = pthread_create(&pthread[3], NULL, transferBA,
            (void*)&transfer_amount[3]) < 0) {

            perror("Thread #3 creation failed.");

            exit (1);

            }

            printf("Transitions are in progress..");

            while ((accountA.balance != final_balanceA) && (accountB.balance
            != final_balanceB)) {

            printf("..");

            }

            printf("\nAll the
            money is transferred !!\n");
            }
            使用 gcc 來編譯這個程序,如下所示:
            # gcc -g -o gdbtest2 gdbtest2.c -L/lib/tls -lpthread
            程序 gdbtest2 會掛起,不會返回一條All the money is transferred !!消息。
            將 gdb 附加到正在運(yùn)行的進(jìn)程上,從而了解這個進(jìn)程內(nèi)部正在發(fā)生什么。

            清單 21. 將 gdb 附加到正在運(yùn)行的進(jìn)程上
            # ps -ef |grep gdbtest2
            root
            9510
            8065
            1 06:30 pts/1
            00:00:00 ./gdbtest2
            root
            9516
            9400
            0 06:30 pts/4
            00:00:00 grep gdbtest2
            # gdb -pid 9510
            GNU gdb 6.2.1
            Copyright 2004 Free Software Foundation, Inc.
            GDB is free software, covered by the GNU General Public License, and you
            are welcome to change it and/or distribute copies of it under certain
            conditions.
            Type "show copying" to see the conditions.
            There is absolutely no warranty for GDB.
            Type "show warranty" for
            details.
            This GDB was configured as "ppc-suse-linux".
            Attaching to process 9510
            Reading symbols from /root/test/gdbtest2...done.
            Using host libthread_db library "/lib/tls/libthread_db.so.1".
            Reading symbols from /lib/tls/libpthread.so.0...done.
            [Thread debugging using libthread_db enabled]
            [New Thread 1073991712 (LWP 9510)]
            [New Thread 1090771744 (LWP 9514)]
            [New Thread 1086577440 (LWP 9513)]
            [New Thread 1082383136 (LWP 9512)]
            [New Thread 1078188832 (LWP 9511)]
            Loaded symbols for /lib/tls/libpthread.so.0
            Reading symbols from /lib/tls/libc.so.6...done.
            Loaded symbols for /lib/tls/libc.so.6
            Reading symbols from /lib/ld.so.1...done.
            Loaded symbols for /lib/ld.so.1
            0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
            (gdb) info thread

            5 Thread 1078188832 (LWP 9511)
            0x0ffe94ec in __lll_lock_wait ()
            from /lib/tls/libpthread.so.0

            4 Thread 1082383136 (LWP 9512)
            0x0ffe94ec in __lll_lock_wait ()
            from /lib/tls/libpthread.so.0

            3 Thread 1086577440 (LWP 9513)
            0x0ffe94ec in __lll_lock_wait ()
            from /lib/tls/libpthread.so.0

            2 Thread 1090771744 (LWP 9514)
            0x0ffe94ec in __lll_lock_wait ()
            from /lib/tls/libpthread.so.0

            1 Thread 1073991712 (LWP 9510)
            0x0ff4ac40 in __write_nocancel ()
            from /lib/tls/libc.so.6
            (gdb)
            從info thread命令中,我們可以了解到除了主線程(thread #1)之外的所有線程都在等待函數(shù)__lll_lock_wait ()完成。
            使用thread apply threadno where命令來查看每個線程到底運(yùn)行到了什么地方:

            清單 22. 查看每個線程運(yùn)行到了什么地方
            (gdb) thread apply 1 where
            Thread 1 (Thread 1073991712 (LWP 9510)):
            #0
            0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
            #1
            0x0ff4ac28 in __write_nocancel () from /lib/tls/libc.so.6
            Previous frame. identical to this frame. (corrupt stack?)
            #0
            0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
            (gdb) thread apply 2 where
            Thread 2 (Thread 1090771744 (LWP 9514)):
            #0
            0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
            #1
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #2
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #3
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #4
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            Previous frame. inner to this frame. (corrupt stack?)
            #0
            0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
            (gdb) thread apply 3 where
            Thread 3 (Thread 1086577440 (LWP 9513)):
            #0
            0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
            #1
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #2
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #3
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #4
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            Previous frame. inner to this frame. (corrupt stack?)
            #0
            0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
            (gdb) thread apply 4 where
            Thread 4 (Thread 1082383136 (LWP 9512)):
            #0
            0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
            #1
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #2
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #3
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #4
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            Previous frame. inner to this frame. (corrupt stack?)
            #0
            0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6

            (gdb) thread apply 5 where
            Thread 5 (Thread 1078188832 (LWP 9511)):
            #0
            0x0ffe94ec in __lll_lock_wait () from /lib/tls/libpthread.so.0
            #1
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #2
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #3
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            #4
            0x0ffe466c in pthread_mutex_lock () from /lib/tls/libpthread.so.0
            Previous frame. inner to this frame. (corrupt stack?)
            #0
            0x0ff4ac40 in __write_nocancel () from /lib/tls/libc.so.6
            每個線程都試圖對一個互斥體進(jìn)行加鎖,但是這個互斥體卻是不可用的,可能是因?yàn)橛辛硗庖粋€線程已經(jīng)對其進(jìn)行加鎖了。從上面的證據(jù)我們可以判斷程序中一定存在死鎖。您還可以看到哪個線程現(xiàn)在擁有這個互斥體。

            清單 23. 查看哪個線程擁有互斥體
            (gdb) print AccountA_mutex
            $1 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2527,
            __m_kind = 0, __m_lock
            = {__status = 1, __spinlock = 0}}
            (gdb) print 0x2527
            $2 = 9511
            (gdb) print AccountB_mutex
            $3 = {__m_reserved = 2, __m_count = 0, __m_owner = 0x2529,
            __m_kind = 0, __m_lock = {__status = 1, __spinlock = 0}}
            (gdb) print 0x2529
            $4 = 9513
            (gdb)
            從上面的命令中,我們可以看出AccontA_mutex是被線程 5(LWP 9511)加鎖(擁有)的,而AccontB_mutex是被線程 3(LWP 9513)加鎖(擁有)的。
            為了解決上面的死鎖情況,可以按照相同的順序?qū)コ怏w進(jìn)行加鎖,如下所示:
            清單 24. 按照相同的順序?qū)コ怏w進(jìn)行加鎖
            .
            .
            void * transferAB (void* amount_ptr) {

            int amount = *((int*)amount_ptr);

            pthread_mutex_lock(&AccountA_mutex);

            pthread_mutex_lock(&AccountB_mutex);

            if (accountA.balance < amount)
            {

            printf("There is not enough memory in Account A!\n");

            pthread_mutex_unlock(&AccountA_mutex);

            pthread_exit((void *)1);

            }

            accountA.balance -=amount;

            sleep(1);

            accountB.balance +=amount;

            pthread_mutex_unlock(&AccountA_mutex);

            pthread_mutex_unlock(&AccountB_mutex);
            }
            void * transferBA (void* amount_ptr) {

            int amount = *((int*)amount_ptr);

            pthread_mutex_lock(&AccountA_mutex);

            pthread_mutex_lock(&AccountB_mutex);

            if (accountB.balance < amount)
            {

            printf("There is not enough memory in Account B!\n");

            pthread_mutex_unlock(&AccountB_mutex);

            pthread_exit((void *)1);

            }

            accountB.balance -=amount;

            sleep(1);

            accountA.balance +=amount;

            pthread_mutex_unlock(&AccountA_mutex);

            pthread_mutex_unlock(&AccountB_mutex);
            }
            .
            .
            或者對每個帳號單獨(dú)進(jìn)行加鎖,如下所示:
            清單 25. 對每個帳號單獨(dú)進(jìn)行加鎖
            .
            .
            void * transferAB (void* amount_ptr) {

            int amount = *((int*)amount_ptr);

            pthread_mutex_lock(&AccountA_mutex);

            if (accountA.balance < amount)
            {

            printf("There is not enough memory in Account A!\n");

            pthread_mutex_unlock(&AccountA_mutex);

            pthread_exit((void *)1);

            }

            accountA.balance -=amount;

            sleep(1);

            pthread_mutex_unlock(&AccountA_mutex);

            pthread_mutex_lock(&AccountB_mutex);

            accountB.balance +=amount;

            pthread_mutex_unlock(&AccountB_mutex);
            }
            void * transferBA (void* amount_ptr) {

            int amount = *((int*)amount_ptr);

            pthread_mutex_lock(&AccountB_mutex);

            if (accountB.balance < amount)
            {

            printf("There is not enough memory in Account B!\n");

            pthread_mutex_unlock(&AccountB_mutex);

            pthread_exit((void *)1);

            }

            accountB.balance -=amount;

            sleep(1);

            pthread_mutex_unlock(&AccountB_mutex);

            pthread_mutex_lock(&AccountA_mutex);

            accountA.balance +=amount;

            pthread_mutex_unlock(&AccountA_mutex);
            }
            .
            .
            .

            posted on 2010-08-05 18:05 葉子 閱讀(920) 評論(0)  編輯 收藏 引用 所屬分類: C\C++

            无码AV中文字幕久久专区| 久久精品国产亚洲av麻豆色欲| 久久99国产综合精品免费| 人人狠狠综合久久亚洲| 精品久久久久久久久久中文字幕 | 久久国产精品无码一区二区三区| 久久久久人妻一区精品果冻| 办公室久久精品| 久久人人爽人人爽人人片AV麻豆| 伊人丁香狠狠色综合久久| 99久久夜色精品国产网站| 久久精品国产一区二区三区| 久久婷婷人人澡人人| 国产一区二区久久久| 亚洲色大成网站WWW久久九九| 影音先锋女人AV鲁色资源网久久| 久久久久亚洲av综合波多野结衣| 漂亮人妻被黑人久久精品| www.久久精品| 日日狠狠久久偷偷色综合免费 | 亚洲人AV永久一区二区三区久久 | 中文字幕久久欲求不满| 精品久久人人妻人人做精品| 亚洲精品WWW久久久久久| 无码AV中文字幕久久专区| 久久精品国产只有精品2020| 久久久久亚洲AV成人网人人网站 | 久久91精品久久91综合| 久久久久女教师免费一区| 青青草原精品99久久精品66| 91久久精品视频| 东方aⅴ免费观看久久av| 狠狠综合久久综合中文88| 无码人妻精品一区二区三区久久| 久久亚洲精品中文字幕三区| 亚洲七七久久精品中文国产| 精品国产乱码久久久久久1区2区| 四虎影视久久久免费| 久久线看观看精品香蕉国产| 无码专区久久综合久中文字幕| 久久久久久久综合日本|