Во-первых, я использую библиотеку pthread для написания многопоточной C-программы. Нити всегда зависали от ожидаемых мьютексов. Когда я использую утилиту strace, чтобы найти поток, находящийся в состоянии FUTEX_WAIT
, я хочу знать, какой поток в данный момент удерживает этот мьютекс. Но я не знаю, как я мог это сделать. Есть ли какие-нибудь утилиты, которые могут это сделать?
Кто-то сказал мне, что виртуальная машина Java поддерживает это, поэтому я хочу знать, поддерживает ли Linux эту функцию.
Вы можете использовать знания о внутреннем устройстве мьютексов, чтобы сделай это. Обычно это не очень хорошая идея, но для отладки подходит.
В Linux с NPTL-реализацией pthreads (которая представляет собой любую современную glibc) вы можете изучить член __ data .__ owner
структуры pthread_mutex_t
, чтобы определить поток, который в настоящее время он заблокирован. Вот как это сделать после присоединения к процессу с помощью gdb
:
(gdb) thread 2
[Switching to thread 2 (Thread 0xb6d94b90 (LWP 22026))]#0 0xb771f424 in __kernel_vsyscall ()
(gdb) bt
#0 0xb771f424 in __kernel_vsyscall ()
#1 0xb76fec99 in __lll_lock_wait () from /lib/i686/cmov/libpthread.so.0
#2 0xb76fa0c4 in _L_lock_89 () from /lib/i686/cmov/libpthread.so.0
#3 0xb76f99f2 in pthread_mutex_lock () from /lib/i686/cmov/libpthread.so.0
#4 0x080484a6 in thread (x=0x0) at mutex_owner.c:8
#5 0xb76f84c0 in start_thread () from /lib/i686/cmov/libpthread.so.0
#6 0xb767784e in clone () from /lib/i686/cmov/libc.so.6
(gdb) up 4
#4 0x080484a6 in thread (x=0x0) at mutex_owner.c:8
8 pthread_mutex_lock(&mutex);
(gdb) print mutex.__data.__owner
$1 = 22025
(gdb)
(Я переключаюсь на зависший поток; выполняю обратную трассировку, чтобы найти pthread_mutex_lock ()
, на котором он застрял; измените кадры стека, чтобы узнать имя мьютекса, который он пытается заблокировать; затем выведите владельца этого мьютекса). Это говорит мне, что виноват поток с LWP ID 22025.
Затем вы можете использовать thread find 22025
, чтобы узнать номер потока gdb
для этого потока и переключиться на него.
Я не знаю ни одного подобного объекта, поэтому не думаю, что вы так легко отделаетесь - и, вероятно, это будет не так информативно, как вы думаете, для помощи в отладке вашей программы. Каким бы низкотехнологичным это ни казалось, протоколирование - ваш друг в отладке таких вещей. Начните собирать свои собственные маленькие функции протоколирования. Они не должны быть причудливыми, они просто должны выполнять свою работу во время отладки.
Извините за C++, но что-то вроде:
void logit(const bool aquired, const char* lockname, const int linenum)
{
pthread_mutex_lock(&log_mutex);
if (! aquired)
logfile << pthread_self() << " tries lock " << lockname << " at " << linenum << endl;
else
logfile << pthread_self() << " has lock " << lockname << " at " << linenum << endl;
pthread_mutex_unlock(&log_mutex);
}
void someTask()
{
logit(false, "some_mutex", __LINE__);
pthread_mutex_lock(&some_mutex);
logit(true, "some_mutex", __LINE__);
// do stuff ...
pthread_mutex_unlock(&some_mutex);
}
Логирование не является идеальным решением, но ничто не является таковым. Обычно это позволяет получить то, что вам нужно знать.