Можно ли определить поток, удерживающий мьютекс? - PullRequest
59 голосов
/ 14 августа 2010

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

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

Ответы [ 4 ]

99 голосов
/ 16 августа 2010

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

В Linux с реализацией pthreads (которая является любым современным glibc) в NPTL, вы можете проверить член __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 22025.

Затем вы можете использовать thread find 22025, чтобы узнать номер потока gdb для этого потока и переключиться на него.

5 голосов
/ 14 августа 2010

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

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

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

2 голосов
/ 17 июня 2012

Обычно вызовы libc / платформы абстрагируются от уровня абстракции ОС.Мертвые блокировки мьютекса можно отслеживать с помощью переменной владельца и 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.

1 голос
/ 09 сентября 2015

Пожалуйста, прочитайте ссылку ниже, это общее решение для поиска владельца замка. Это работает, даже если вы заблокировали библиотеку, и у вас нет исходного кода.

https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques/Deadlocks

...