web-dev-qa-db-fra.com

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

Tout d'abord, j'utilise la bibliothèque pthread pour écrire un programme C multithreading. Les fils étaient toujours suspendus par leurs mutex attendus. Lorsque j'utilise l'utilitaire strace pour trouver un thread se trouve dans FUTEX_WAIT status, je veux savoir quel thread détient ce mutex à l'époque. Mais je ne sais pas comment je pourrais le faire. Y a-t-il des utilitaires qui pourraient le faire?

Quelqu'un m'a dit Java virtual machine support this, donc je veux savoir si Linux supporte cette fonctionnalité.

62
terry

Vous pouvez utiliser la connaissance des internes mutex pour ce faire. Normalement, ce ne serait pas une très bonne idée, mais c'est bien pour le débogage.

Sous Linux avec l'implémentation NPTL de pthreads (qui est n'importe quelle glibc moderne), vous pouvez examiner le membre __data.__owner De la structure pthread_mutex_t Pour trouver le thread qui le verrouille actuellement. Voici comment le faire après avoir 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 bloqué; faites un retour en arrière pour trouver la pthread_mutex_lock() sur laquelle elle est bloquée; changez les cadres de la pile pour trouver le nom du mutex qu'il tente de verrouiller; puis imprimez le propriétaire de ce mutex) . Cela me dit que le thread avec LWP ID 22025 est le coupable.

Vous pouvez ensuite utiliser thread find 22025 Pour trouver le numéro de thread gdb pour ce thread et passer à celui-ci.

102
caf

Je ne connais aucune installation de ce type, donc je ne pense pas que vous réussirez aussi facilement - et ce ne serait probablement pas aussi instructif que vous le pensez en aidant à déboguer votre programme. Aussi bas que cela puisse paraître, la journalisation est votre ami dans le débogage de ces choses. Commencez à collecter vos propres petites fonctions de journalisation. Ils n'ont pas besoin d'être sophistiqués, ils 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. Cela vous donne généralement ce que vous devez savoir.

5
Duck

Normalement, les appels libc/plateformes sont extraits par la couche d'abstraction du système d'exploitation. Les verrous morts mutex peuvent être suivis à l'aide d'une variable propriétaire et de pthread_mutex_timedlock. Chaque fois que le thread se verrouille, il doit mettre à jour la variable avec son propre tid (gettid () et peut également avoir une autre variable pour le stockage d'ID pthread). Ainsi, lorsque les autres threads se bloquent et expirent sur pthread_mutex_timedlock, il peut afficher la valeur de propriétaire tid et pthread_id. de cette façon, vous pouvez facilement trouver le fil propriétaire. veuillez trouver l'extrait de 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 façons de trouver les verrous morts, peut-être que ce lien pourrait aider http://yusufonlinux.blogspot.in/2010/11/debugging-core-using-gdb.html .

2
Yusuf Khan

Veuillez lire le lien ci-dessous, Ceci a une solution générique pour trouver le propriétaire de la serrure. Cela fonctionne même si vous verrouillez une bibliothèque et que vous n'avez pas le code source.

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

1
Jossy Sebastian