90 votes

Est-il possible de déterminer le thread qui détient un mutex ?

Tout d'abord, j'utilise la bibliothèque pthread pour écrire des programmes C multithreading. Les threads sont toujours bloqués par leurs mutexs en attente. Lorsque j'utilise l'utilitaire strace pour trouver un thread dans le fichier FUTEX_WAIT je veux savoir quel thread détient ce mutex à ce moment-là. Mais je ne sais pas comment je pourrais le faire. Existe-t-il des utilitaires qui peuvent le faire ?

Quelqu'un m'a dit que la machine virtuelle Java prend en charge cette fonctionnalité. Je veux donc savoir si Linux la prend en charge.

149voto

caf Points 114951

Pour ce faire, vous pouvez utiliser votre connaissance des internes du mutex. Normalement, ce n'est pas une très bonne idée, mais c'est parfait pour le débogage.

Sous Linux avec l'implémentation NPTL de pthreads (qui est n'importe quelle glibc moderne), vous pouvez examiner le fichier __data.__owner membre de la pthread_mutex_t structure pour découvrir le fil de discussion dans lequel il est actuellement verrouillé. Voici comment procéder après s'être attaché au processus avec 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)

(Je passe au thread suspendu ; je fais un backtrace pour trouver le pthread_mutex_lock() il est bloqué ; changer les trames de pile pour trouver le nom du mutex qu'il essaie de verrouiller ; puis imprimer le propriétaire de ce mutex). Cela me dit que le thread avec l'ID LWP 22025 est le coupable.

Vous pouvez alors utiliser thread find 22025 pour connaître le gdb numéro de fil pour ce fil et passer à celui-ci.

5voto

Duck Points 17054

Je ne connais pas d'installation de ce type, donc je ne pense pas que vous vous en sortirez aussi facilement - et cela ne serait probablement pas aussi instructif que vous le pensez pour aider à déboguer votre programme. Aussi peu technique que cela puisse paraître, la journalisation est votre amie pour déboguer ces choses. Commencez à rassembler vos propres petites fonctions de journalisation. Elles n'ont pas besoin d'être sophistiquées, elles doivent juste faire le travail pendant le débogage.

Désolé pour le C++ mais quelque chose comme :

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);
}

La journalisation n'est pas une solution parfaite, mais rien ne l'est. Elle vous permet généralement d'obtenir ce que vous avez besoin de savoir.

3voto

Jossy Sebastian Points 115

Veuillez lire le lien ci-dessous, il contient une solution générique pour trouver le propriétaire de la serrure. Il fonctionne même si le verrou dans le côté d'une bibliothèque et vous n'avez pas le code source.

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

2voto

Yusuf Khan Points 229

Normalement, les appels de libc/platforms sont abstraits par la couche d'abstraction du système d'exploitation. Les mutex dead locks peuvent être suivis en utilisant une variable propriétaire et pthread_mutex_timedlock. Chaque fois qu'un thread se verrouille, il doit mettre à jour la variable avec son propre tid (gettid() et peut aussi avoir une autre variable pour le stockage de l'id du pthread). Ainsi, lorsque les autres threads se bloquent et s'arrêtent sur pthread_mutex_timedlock, il peut imprimer la valeur du tid propriétaire et du pthread_id. De cette façon, vous pouvez facilement trouver le thread propriétaire. veuillez trouver le code ci-dessous, notez que toutes les conditions d'erreur ne sont pas gérées

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);  
        }
};

Il existe d'autres moyens de trouver les serrures mortes, ce lien peut peut-être vous aider. http://yusufonlinux.blogspot.in/2010/11/debugging-core-using-gdb.html .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X