Почему pthread вызывает утечку памяти

Всякий раз, когда я создаю pthread, valgrind выводит утечку памяти,

Например, приведенный ниже код:

#include <stdio.h>
#include <unistd.h>
#include <pthread.h> 

void *timer1_function (void *eit){
  (void) eit;
    printf("hello world\n");
    pthread_exit(NULL);
}

int main(void){
   pthread_t timer1;
   pthread_create( &timer1, NULL, timer1_function,  NULL);  ///////line13
   int i=0;
   for(i=0;i<2;i++){usleep(1);}
   return 0;
}

выходы valgrind

==1395== HEAP SUMMARY:
==1395==     in use at exit: 136 bytes in 1 blocks
==1395==   total heap usage: 6 allocs, 5 frees, 1,134 bytes allocated
==1395== 
==1395== 136 bytes in 1 blocks are possibly lost in loss record 1 of 1
==1395==    at 0x402A629: calloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==1395==    by 0x4011304: allocate_dtv (dl-tls.c:297)
==1395==    by 0x4011AAB: _dl_allocate_tls (dl-tls.c:461)
==1395==    by 0x4052470: [email protected]@GLIBC_2.1 (allocatestack.c:571)
==1395==    by 0x8048566: main (test.c:13)
==1395== 
==1395== LEAK SUMMARY:
==1395==    definitely lost: 0 bytes in 0 blocks
==1395==    indirectly lost: 0 bytes in 0 blocks
==1395==      possibly lost: 136 bytes in 1 blocks
==1395==    still reachable: 0 bytes in 0 blocks
==1395==         suppressed: 0 bytes in 0 blocks

почему pthread_create вызывает проблему, хотя я использовал справочную страницу как ссылку и как ее исправить?

Ответы

Ответ 1

Нить - выделенный ресурс, и вы не освобождали его перед выходом. Вы должны позвонить pthread_join; это также устранит необходимость в вашей хакерской и неправильной петле сна.

Возможно, что даже после того, как вы исправите это, valgrind все равно увидит "утечку", поскольку некоторые реализации потоков POSIX (я предполагаю, что вы используете glibc/NPTL) и повторно используете ресурсы потоков, а не полностью освобождаете их, Я не уверен, работает ли valgrind или нет.

Ответ 2

Я думаю, что valgrind анализирует состояние вашей программы во время ее выхода, что, вероятно, до того, как поток завершит свое выполнение: двух микросекунд может быть недостаточно для записи "Hello, world!\n" в консоль. Добавление вызова в pthread_join должно устранить эту утечку:

pthread_join(timer1, NULL);

Ответ 3

Я видел похожие результаты, когда мне не удалось вызвать pthread_join.

Когда я вызываю pthread_join, Valgrind не укажет на ошибки памяти или утечки. У меня был чистый результат с помощью pthread_kill, чтобы узнать, существует ли поток, а затем вызывает объединение, чтобы очистить и освободить ресурсы.

int
stop_worker(worker_t *self)
{
    if (self) {
        // signal the thread to quit
            // (here using a variable and semaphore)
        self->thread_quit=TRUE;
        sem_post(&self->sem);

        // wait for it to stop
        // (could use counter, etc. to limit wait)
        int test=0;
        while (pthread_kill(self->thread,0) == 0) {
            MDEBUG(MD_XF_LOGGER,"waiting for thread to exit...\n",test);
            delay_msec(50);
        }

        // even though thread is finished, need to call join
        // otherwise, it will not release its memory (and valgrind indicates a leak)
        test=pthread_join(self->thread,NULL);
        return 0;           
    }
    return -1;
}

Ответ 4

Происходящая утечка связана с структурой DTV (Dynamic Thread Vector), которая выделяется в локальном хранилище дочернего потока (tls).

Использование pthread_join() в основном потоке (т.е. поток, породивший дочерний элемент), обеспечит исправление утечки. Для случаев использования, когда вызов pthread_join() не требуется, вызов pthread_detach с дочерним pthread_t гарантирует освобождение памяти.

От человека для pthread_detach:

Функция pthread_detach() отмечает поток, идентифицированный потоком как снято. Когда отдельный поток завершается, его ресурсы автоматически возвращается в систему без необходимости другой поток для соединения с завершенным потоком.

Ответ 5

утечка памяти является результатом того факта, что если поток оставлен без отмены, то соответствующая динамически распределенная память не освобождается. Используйте pthread_cancel() вместе с pthread_cleanup_push (CleanupHandler, NULL) и pthread_cleanup_pop (0), чтобы выполнить очистку потока после отмены.