Нет необходимости в free () переменной кучи, выделенной и возвращенной из потока? - PullRequest
0 голосов
/ 09 июня 2019

Насколько я знаю, malloc() (или любая функция выделения кучи) и free() должны быть сопряжены. Я думал, что то же самое в многопоточных программах. Но похоже, что я не должен free() переменная кучи, которая была размещена в другом потоке.

Когда я запускаю приведенный ниже код (в среде wsl ubuntu),

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void* thread_main(void* arg) {
    int i = 0;
    for (; i < *((int*)arg); i++) {
        printf("thread running... %d\n", i);
    }

    char* msg = (char*)malloc(sizeof(char) * 50);
    msg = "thread end\n";

    return (void*)msg;
}

int main() {
    pthread_t thread_id;
    int thread_arg = 5;
    void* thread_return;

    pthread_create(&thread_id, NULL, thread_main, (void*)&thread_arg);
    pthread_join(thread_id, &thread_return);

    printf("thread returned message : %s", (char*)thread_return);

    free(thread_return);  // if I comment out this line, the program succeeds.
    return 0;
}

Я получаю стандартный вывод

thread running... 0
thread running... 1
thread running... 2
thread running... 3
thread running... 4
thread returned message : thread end
munmap_chunk(): invalid pointer
Aborted (core dumped)

Однако, если я закомментирую часть free(thread_return);, программа завершится успешно и не выдаст сообщение об ошибке сброса.

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

Ответы [ 2 ]

2 голосов
/ 09 июня 2019
char* msg = (char*)malloc(sizeof(char) * 50);
msg = "thread end\n";

Вторая строка здесь перезаписывает указатель, выделенный malloc(), указателем на постоянную строку, вызывая утечку памяти, которая была первоначально выделена.Значение, возвращаемое этим потоком, указывает на эту константную строку, а не на память, выделенную malloc();попытка free() этого значения не удастся, поскольку оно не было выделено malloc().

Используйте strncpy(), чтобы записать строку в память, выделенную malloc().Как только вы это сделаете, вы можете (и должны) освободить полученную память с помощью free() в главном потоке.

0 голосов
/ 09 июня 2019

Короче говоря

Всегда освобождайте выделенную память в той же логической единице, которая ее выделила.

Причины

ЕслиВы освобождаете память, которая была выделена в другом потоке, или даже говорите, что динамически распределенный буфер, полученный вами в качестве параметра для вашей функции, вы решаете освободить - вы можете вызвать много проблем.

Использование этого в будущемпеременная может привести к сбою вашей программы, так как она пыталась добраться до нераспределенной памяти.

Это действительно лучшая практика, как я писал в обзоре, особенно при написании кода для больших проектов с несколькими разработчиками - так как вы можете 't всегда знать, что произойдет в будущем с динамически распределенным буфером.

Сбой

Решение проблемы с вашей аварией, это не вызвано тем, что вы пытаетесь освободить памятьвыделено в другом потоке - это просто происходит, поскольку, используя строку:

msg = "thread end\n";

сразу после выделения памяти и назначения ее в msg, вы потерялиВаш указатель на выделенную память.Теперь при освобождении «msg» вы пытаетесь освободить переменную, расположенную в стеке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...