Получение утечек даже после pthread_detach

Я пытаюсь сделать код самоочищающегося потока для высвобождения ресурсов pthread_t, если я завершаю всю программу из стороннего потока с помощью pthread_detach, но я все еще получаю отчеты об утечках памяти от valgrind с возможными потерянными байтами. Вот мой образец кода:

pthread_t main_thread;
pthread_t second_thread;

void* thread_func() {
    pthread_detach(pthread_self());
    exit(0);
}

int main() {
    main_thread = pthread_self(); // record main thread in case needed later
    pthread_create(&second_thread, NULL, thread_func, NULL);
    while(1); // making main thread wait using a busy-wait (in case pthread_join) interferes
              // with pthread_detach (that's another question though: does pthread_join called
              // from another thread overlaps with pthread_detach from the same thread?)


}


Может ли кто-нибудь помочь мне указать, где я забыл освободить какие-либо выделенные ресурсы?


person falhumai    schedule 28.08.2016    source источник


Ответы (2)


Отсоединение потока с помощью pthread_detach() информирует библиотеку pthreads о том, что ресурсы, связанные с этим потоком, могут быть освобождены после завершения потока. Однако вы выходите из всего процесса, и поэтому Valgrind жалуется на утечку ресурсов. Хотя при выходе из процесса все ресурсы будут очищены в современных операционных системах, Valgrind достаточно привередлив.

Таким образом, вместо вызова exit(), который завершает весь процесс, а не только вызывающий поток, если вы вызываете pthread_exit(NULL); или return NULL; из thread_func(), вы должны увидеть, что библиотека pthreads освобождает выделенные ресурсы.

перекрывается ли pthread_join, вызванный из другого потока, с pthread_detach из того же потока?

Вы не можете присоединиться к потоку, который был отсоединен (либо он был создан с установленным атрибутом detached, либо отсоединен с помощью pthread_detach()). В документации pthread_detach() указано, что это не указано :

Попытка отсоединить уже отсоединенный поток приводит к неуказанному поведению.

person P.P    schedule 28.08.2016
comment
Но мое внимание здесь сосредоточено на том, что если я хочу выйти из побочного потока из всей программы, а не только из текущего потока, без жалоб на valgrind (я знаю, что последняя очистка не будет такой важной, но было бы неплохо убирать все при выходе из программы!!)?? - person falhumai; 29.08.2016
comment
Как правило, вы не хотите завершать весь процесс из потока, так как это может внезапно прервать все другие потоки, не допуская каких-либо очисток. На самом деле exit() не является многопоточным! Если вы хотите выйти по условию, вы можете установить флаг (атомарно) в этом потоке и сообщить другим потокам, что вы хотите выйти (чтобы они могли выполнять ceanups), а затем один из потоков, например, основной поток можно безопасно выйти. - person P.P; 29.08.2016

Итак, я только что нашел удивительное решение проблемы, с которой столкнулся несколько дней назад, и хотел бы поделиться им.

Просто напоминание о том, в чем заключается исходная проблема: проблема заключается в том, как очистить утечки потоков после вызова полного выхода из процесса (это не будет фактической утечкой в ​​​​производственном коде, но это просто для того, чтобы сделать valgrind, например, счастливым! !).

Итак, решение, которое я придумал:

Сделайте основной поток таким же, как и любой другой поток, создав поток только для «основного» потока (я знаю, что это увеличит использование памяти и не будет очень эффективным). Фактический основной поток будет постоянно проверять любой сигнал выхода, отправленный из любого потока, и если это так, очистите все потоки и просто завершите работу. Другие потоки отправят сигнал выхода, когда это необходимо, и будут ждать, пока фактический основной поток очистит их (включая макет «основного» потока, который содержит предполагаемый код основного потока).

Вот псевдокод, иллюстрирующий то, что я упомянул выше:

threadId1;
threadId2;
mainThreadId;
willExit = false;
exitStatusCode;
mainThreadArgs;

exit_cleanup(exitStatusCodeArg) {
    exitStatusCode = exitStatusArg;
    willExit = true;
    while(true);
}

threadFunc1() {
    // Example thread code 1
    exit_cleanup(0);
}

threadFunc2() {
    // Example thread code 2
    if (/*some error*/)
        exit_cleanup(-1);
}

mainThreadFunc() {
    // some code (could be long, and may create side threads here)

    // by default, main thread should call exit_cleanup(0) at the end, as
    // exiting the main thread should also cancel all running threads
    exit_cleanup(0);
}

cleanUp() {
    while (willExit != false);
    for (all thread saved globally) {
        cancel and join current thread;
    }
    exit(exitStatusCode);
}

main(args) {
    mainThreadArgs = args;
    create_thread(mainThreadId, mainThreadFunc);
    cleanUp();
}



Судя по приведенному выше коду, я не вижу никаких причин, по которым valgrind или любой другой инструмент для проверки утечек памяти будет жаловаться на любые «все еще доступные» или «возможно, потерянные» утечки.

Любые исправления в моем решении приветствуются!

person falhumai    schedule 01.09.2016