デバッガにはロードモジュールをそのまま、そのレベルでデバッグするabsolute debugger(adb)とソースレベルのエントリを利用してデバッグを行なう symbolic debugger(dbx/gdb)の2種類があります。
ソースコードが存在するプログラムのデバッグにはシンボリックデバッガが適しています。
スポンサードリンク
マルチスレッドプログラミングのDeakLockは、本当に厄介なものです。
運が良ければ、GDBからデッドロックの情報を取得する可能性があります。
ミューテックス(mutex)はリエントラント(再入可能)ではありません。
再入しようとするとデッドロックが発生することを利用して、作成したコードは次のとおりです。
#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <thread>
#include <mutex>
std::mutex gMutex;
int Reenter(){
std::lock_guard<std::mutex> lLock(gMutex);
return 10;
}
int Callback()
{
std::lock_guard<std::mutex> lLock(gMutex);
return Reenter();
}
int main(int argc, char**argv) {
// Prints hello message...
std::cout << "Hello CMake World!" << std::endl;
std::thread lThread(Callback);
lThread.join();
std::cout << "sub thread is gone!" << std::endl;
return 0;
}
GDB解析可能なコンパイル方法は次のとおりです。
g ++ deadlock.cpp -ggdb -lpthread -std = c ++ 11 -o deadlock
実行方法は次のようになります。
hoge@:~/$ ./deadlock & Hello CMake World!
これによりデッドロックが発生しました。
pidを取得します。
hoge@:~/$ ps -a | grep deadlock 3590 pts/4 00:00:00 deadlock
別の端末を使用(もしくは「&」をつけた場合は同じ端末を使用)してpidに接続します。
hoge@:~/$ sudo gdb -q deadlock 3590 [sudo] password for hoge: Reading symbols from deadlock...done. Attaching to program: /home/hoge/deadlock, process 3590 [New LWP 3591] [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 0x00007f1be31f7d2d in __GI___pthread_timedjoin_ex (threadid=139757737469696, thread_return=0x0, abstime=0x0, block=) at pthread_join_common.c:89 89 pthread_join_common.c: No such file or directory. (gdb)
[New LWP]の「LMP」とは「軽量プロセス」ともいいます。
もともとはUNIXにおいて、プロセスよりもさらに小さいプログラムの実行単位としてLWPが導入されました。
ここで、pthread_join_common.c:89 で、止まっていることがわかります。
次にバックトレース(呼び出し履歴の表示)を表示します。
backtraceコマンドを使用すると現在のスレッドの呼び出し履歴が確認できます。
(gdb) bt #0 0x00007f1be31f7d2d in __GI___pthread_timedjoin_ex (threadid=139757737469696, thread_return=0x0, abstime=0x0, block=<optimized out>) at pthread_join_common.c:89 #1 0x00007f1be2f23933 in std::thread::join() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #2 0x000055e67534516d in main (argc=1, argv=0x7ffe62213c08) at deadlock.cpp:26 (gdb)
全スレッドの情報を出力するには次のようなコマンドを打ちます。
(gdb) info threads
Id Target Id Frame
* 1 Thread 0x7f1be360c740 (LWP 3590) "deadlock" 0x00007f1be31f7d2d in __GI___pthread_timedjoin_ex (threadid=139757737469696, thread_return=0x0,
abstime=0x0, block=<optimized out>) at pthread_join_common.c:89
2 Thread 0x7f1be24be700 (LWP 3591) "deadlock" __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
mutex情報を出力するには次のようなコマンドを打ちます。
(gdb) p gMutex
$1 = {<std::__mutex_base> = {_M_mutex = pthread_mutex_t = {Type = Normal, Status = Acquired, possibly with waiters, Owner ID = 3591, Robust = No, Shared = No,
Protocol = None}}, <No data fields>}
スレッドを切り替えるには次のようなコマンドを打ちます。
(gdb) thread 2 [Switching to thread 2 (Thread 0x7f1be24be700 (LWP 3591))] #0 __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135 135 ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S: No such file or directory.
threadのスタックを確認する次のようなコマンドを打ちます。
(gdb) bt
#0 __lll_lock_wait () at ../sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:135
#1 0x00007f1be31f9023 in __GI___pthread_mutex_lock (mutex=0x55e675547140 <gMutex>) at ../nptl/pthread_mutex_lock.c:78
#2 0x000055e675344fff in __gthread_mutex_lock (__mutex=0x55e675547140 <gMutex>) at /usr/include/x86_64-linux-gnu/c++/7/bits/gthr-default.h:748
#3 0x000055e675345300 in std::mutex::lock (this=0x55e675547140 <gMutex>) at /usr/include/c++/7/bits/std_mutex.h:103
#4 0x000055e67534535c in std::lock_guard<std::mutex>::lock_guard (this=0x7f1be24bdd90, __m=...) at /usr/include/c++/7/bits/std_mutex.h:162
#5 0x000055e675345062 in Reenter () at deadlock.cpp:13
#6 0x000055e6753450c0 in Callback () at deadlock.cpp:20
#7 0x000055e6753455c1 in std::__invoke_impl<int, int (*)()> (__f=@0x55e67693c288: 0x55e675345090 <Callback()>) at /usr/include/c++/7/bits/invoke.h:60
#8 0x000055e6753453cf in std::__invoke<int (*)()> (__fn=@0x55e67693c288: 0x55e675345090 <Callback()>) at /usr/include/c++/7/bits/invoke.h:96
#9 0x000055e675345a94 in std::thread::_Invoker<std::tuple<int (*)()> >::_M_invoke<0ul> (this=0x55e67693c288) at /usr/include/c++/7/thread:234
#10 0x000055e675345a52 in std::thread::_Invoker<std::tuple<int (*)()> >::operator() (this=0x55e67693c288) at /usr/include/c++/7/thread:243
#11 0x000055e675345a22 in std::thread::_State_impl<std::thread::_Invoker<std::tuple<int (*)()> > >::_M_run (this=0x55e67693c280)
at /usr/include/c++/7/thread:186
#12 0x00007f1be2f236df in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#13 0x00007f1be31f66db in start_thread (arg=0x7f1be24be700) at pthread_create.c:463
#14 0x00007f1be297ea3f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb)
deadlock.cpp:13の「std::lock_guard
スポンサードリンク
人気の高い書籍および参考文献を紹介します。
スポンサードリンク