Подход к инструменту
Вы можете использовать Valgrind, чтобы помочь с этим (через инструмент Helgrind), но он требует незначительной модификации кода.Для каждого потока вы делаете блокировку потока уникальным мьютексом при создании потока и освобождаете мьютекс при выходе из потока.Затем, при запуске под Helgrind, вы получите предупреждение, если поток не завершился после завершения программы, поскольку поток все еще будет удерживать блокировку мьютекса.Рассмотрим этот пример подпрограммы запуска потока:
void * thread_start (void *arg)
{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
// ...
// Here the thread does whatever it normally does
// ...
// Unlock the mutex before exiting
pthread_mutex_unlock(&mutex);
}
Просто запустите программу, используя инструмент Helgrind от Valgrind, примерно так:
$ valgrind --tool=helgrind ./<program-name>
Если поток не завершился после завершения программы, тогда Helgrindвыдает следующее предупреждение:
==2203== Thread #2 was created
==2203== at 0x31C96D3CDE: clone (in /lib64/libc-2.5.so)
==2203== by 0x31CA206D87: pthread_create@@GLIBC_2.2.5 (in /lib64/libpthread-2.5.so)
==2203== by 0x4A0B206: pthread_create_WRK (hg_intercepts.c:229)
==2203== by 0x4A0B2AD: pthread_create@* (hg_intercepts.c:256)
==2203== by 0x40060A: main (main.c:26)
==2203==
==2203== Thread #2: Exiting thread still holds 1 lock
==2203== at 0x4005DD: thread_start (main.c:13)
==2203== by 0x4A0B330: mythread_wrapper (hg_intercepts.c:201)
==2203== by 0x31CA20673C: start_thread (in /lib64/libpthread-2.5.so)
==2203== by 0x31C96D3D1C: clone (in /lib64/libc-2.5.so)
Используя этот метод, вы получите ложные срабатывания, если не добавите код разблокировки мьютекса в любом месте, где поток может выйти (например, с помощью pthread_exit
), но исправите такойложное срабатывание легко, когда его идентифицируют.
Альтернативный подход (рекомендуется)
С учетом всего вышесказанного, вероятно, я сам не выбрал бы такой подход,Вместо этого я написал бы программу так, чтобы она не могла завершиться, пока не завершатся все потоки.Самый простой способ добиться этого - вызвать pthread_exit
из основного потока перед возвратом из main
.Это будет означать, что процесс останется живым, пока любой другой поток все еще работает.
Если вы воспользуетесь этим подходом, и процесс не завершится, когда вы этого ожидаете, то вы знаете, чтопоток все еще работает.Затем вы можете подключить к процессу отладчик, чтобы определить, какие потоки все еще работают и что они делают.