Можно ли определить поток, содержащий мьютекс?

Во-первых, я использую библиотеку pthread для написания многопоточной C-программы. Нити всегда зависали от ожидаемых мьютексов. Когда я использую утилиту strace, чтобы найти поток, находящийся в состоянии FUTEX_WAIT , я хочу знать, какой поток в данный момент удерживает этот мьютекс. Но я не знаю, как я мог это сделать. Есть ли какие-нибудь утилиты, которые могут это сделать?

Кто-то сказал мне, что виртуальная машина Java поддерживает это, поэтому я хочу знать, поддерживает ли Linux эту функцию.

63
задан Mateusz Piotrowski 8 September 2017 в 19:12
поделиться

2 ответа

Вы можете использовать знания о внутреннем устройстве мьютексов, чтобы сделай это. Обычно это не очень хорошая идея, но для отладки подходит.

В 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 для этого потока и переключиться на него.

105
ответ дан 24 November 2019 в 16:21
поделиться

Я не знаю ни одного подобного объекта, поэтому не думаю, что вы так легко отделаетесь - и, вероятно, это будет не так информативно, как вы думаете, для помощи в отладке вашей программы. Каким бы низкотехнологичным это ни казалось, протоколирование - ваш друг в отладке таких вещей. Начните собирать свои собственные маленькие функции протоколирования. Они не должны быть причудливыми, они просто должны выполнять свою работу во время отладки.

Извините за 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);
}

Логирование не является идеальным решением, но ничто не является таковым. Обычно это позволяет получить то, что вам нужно знать.

5
ответ дан 24 November 2019 в 16:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: