Можно ли определить поток, содержащий мьютекс?
Во-первых, я использую библиотеку pthread для записи многопоточной программы C. Нитки всегда зависали от ожидающих мьютексов. Когда я использую утилиту strace, чтобы найти поток в состоянии FUTEX_WAIT
, я хочу знать, какой поток удерживает этот мьютекс в то время. Но я не знаю, как я мог это сделать. Существуют ли какие-либо утилиты?
Кто-то сказал мне, что виртуальная машина Java поддерживает это, поэтому я хочу знать, поддерживает ли Linux эту функцию.
Ответы
Ответ 1
Для этого вы можете использовать знание внутренних элементов мьютекса. Обычно это не очень хорошая идея, но это хорошо для отладки.
В 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
для этого потока и переключиться на него.
Ответ 2
Я не знаю ни одного такого объекта, поэтому я не думаю, что вы так легко справитесь - и, вероятно, это будет не так информативно, как вы думаете, помогая отлаживать вашу программу. Как низкотехнологичный, как может показаться, регистрация - ваш друг в отладке этих вещей. Начните собирать свои собственные небольшие функции регистрации. Им не обязательно быть фантазией, им просто нужно выполнить работу во время отладки.
Извините за С++, но что-то вроде:
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);
}
Журналирование - не идеальное решение, но ничего нет. Как правило, вы получаете то, что вам нужно знать.
Ответ 3
Обычно вызовы libc/platform абстрагируются уровнем абстракции OS. Мертвые блокировки мьютексов можно отслеживать с использованием переменной владельца и pthread_mutex_timedlock. Всякий раз, когда поток блокируется, он должен обновлять переменную собственным tid (gettid() и может также иметь другую переменную для хранения идентификатора pthread). Поэтому, когда другие потоки блокируются и выходят на pthread_mutex_timedlock, он может печатать значение владельца tid и pthread_id. таким образом вы можете легко узнать поток владельца. пожалуйста, найдите нижеприведенный фрагмент кода, обратите внимание, что все условия ошибки не обрабатываются
pid_t ownerTid;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
class TimedMutex {
public:
TimedMutex()
{
struct timespec abs_time;
while(1)
{
clock_gettime(CLOCK_MONOTONIC, &abs_time);
abs_time.tv_sec += 10;
if(pthread_mutex_timedlock(&mutex,&abs_time) == ETIMEDOUT)
{
log("Lock held by thread=%d for more than 10 secs",ownerTid);
continue;
}
ownerTid = gettid();
}
}
~TimedMutex()
{
pthread_mutex_unlock(&mutex);
}
};
Существуют и другие способы обнаружения мертвых замков, возможно, эта ссылка может помочь http://yusufonlinux.blogspot.in/2010/11/debugging-core-using-gdb.html.
Ответ 4
Пожалуйста, прочитайте ниже ссылку, Это имеет общее решение для поиска владельца замка. Он работает, даже если блокируется в библиотеке, и у вас нет исходного кода.
https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Deadlocks