2010-08-14 12 views
44

En primer lugar, utilizo la biblioteca pthread para escribir el programa C de subprocesos múltiples. Los hilos siempre cuelgan por sus mutexs esperadas. Cuando uso la utilidad strace para encontrar un hilo en el estado FUTEX_WAIT, quiero saber qué hilo contiene ese mutex en ese momento. Pero no sé cómo podría hacerlo. ¿Hay alguna utilidad que pueda hacer eso?¿Es posible determinar el hilo que contiene un mutex?

Alguien me dijo que la máquina virtual Java es compatible con esto, por lo que quiero saber si Linux admite esta característica.

Respuesta

6

No conozco ninguna de estas facilidades, así que no creo que se salga tan fácilmente, y probablemente no sea tan informativo como cree para ayudar a depurar su programa. Por poco tecnológico que parezca, el registro es tu amigo para depurar estas cosas. Comience a recopilar sus propias pequeñas funciones de registro. No tienen que ser elegantes, solo tienen que hacer el trabajo mientras se depuran.

Lo siento por el C++, pero algo como:

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

registro no es una solución perfecta, pero no hay nada. Por lo general, obtiene lo que necesita saber.

+0

El registro de hecho es una herramienta bastante útil para la depuración. Gracias por tus sugerencias – terry

+1

+1 ¿A quién no le gusta el registro? Se podría hacer sin cambios de código usando LD_PRELOAD (y algo de paciencia).Ajustar las funciones 'pthread_mutex_ *' con algo que registra las llamadas de función, la dirección mutex 'y un identificador de subproceso ('pthread_t' pasa a ser un tipo integral en Linux, no una suposición portátil, sino una gran conveniencia). – pilcrow

+7

posible problema con el registro es que podría interrumpir el tiempo y hacer que el problema desaparezca. – Spudd86

74

Puede usar el conocimiento de las partes internas del mutex para hacer esto. Por lo general, esta no sería una buena idea, pero está bien para la depuración.

En Linux con la implementación NPTL de pthreads (que es cualquier glibc moderno), puede examinar el miembro __data.__owner de la estructura pthread_mutex_t para averiguar el hilo que actualmente tiene bloqueado. Esta es la forma de hacerlo después de conectarla al proceso con 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) 

(me cambio a la subproceso colgado, hacer una traza inversa para encontrar la pthread_mutex_lock() se ha pegado en; marcos cambio de pila a averiguar el nombre de la mutex que está intentando bloquear, luego imprima el propietario de ese mutex). Esto me dice que el hilo con LWP ID 22025 es el culpable.

Puede usar thread find 22025 para averiguar el número de hilo gdb para esa secuencia y cambiar a ella.

+1

¿Hay alguna manera de correlacionar __data __.__ owner__ con pthread thread id? Al jugar con esto simplemente codifiqué log << mutex .__ data __. Owner << endl y eso parece funcionar bien. Pero el propietario de datos tiene un valor como 9841, mientras que el tid es como 140505876686608. ¿Cuál es la relación entre los dos valores? – Duck

+5

@Duck: el valor en '.__ data .__ owner' es un TID. Cuando se inicia cada subproceso, simplemente puede hacer que registre su TID (utilizando 'tid = syscall (SYS_gettid);'), así como su 'pthread_t' (from' pthread_self() '). – caf

+1

Excelente. Gracias. – Duck

2

Normalmente, las llamadas a libc/plataformas se abstraen mediante la capa de abstracción del sistema operativo. Los bloqueos muertos mutex se pueden rastrear usando una variable de propietario y pthread_mutex_timedlock. Cada vez que el hilo se bloquea, debe actualizar la variable con propio tid (gettid() y también puede tener otra variable para el almacenamiento de pthread id). Entonces, cuando los otros subprocesos bloquean y se agota el tiempo de espera en pthread_mutex_timedlock, puede imprimir el valor de owner tid y pthread_id. De esta forma, puedes encontrar fácilmente el hilo del propietario. Por favor, encontrar el siguiente fragmento de código, tenga en cuenta que todas las condiciones de error no se manejan

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

Hay otras maneras de descubrir las cerraduras, tal vez este enlace podría ayudar a http://yusufonlinux.blogspot.in/2010/11/debugging-core-using-gdb.html.

Cuestiones relacionadas