pthread: уничтожение глобального статического мьютекса

Этот код был взят из 3-го издания Расширенного программирования в среде UNIX, написанного Ричардом Стивенсом. Это пример того, как сделать реентерабельную версию getenv(), Это показано здесь только в целях обучения.

/* Copyright (c) W.R.Stevens */
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>

extern char **environ;

pthread_mutex_t env_mutex;

static pthread_once_t init_done = PTHREAD_ONCE_INIT;

static void
thread_init(void)
{
    pthread_mutexattr_t attr;

    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
    pthread_mutex_init(&env_mutex, &attr);
    pthread_mutexattr_destroy(&attr);
}

int
getenv_r(const char *name, char *buf, int buflen)
{
    int i, len, olen;

    pthread_once(&init_done, thread_init);
    len = strlen(name);
    pthread_mutex_lock(&env_mutex);
    for (i = 0; environ[i] != NULL; i++) {
        if ((strncmp(name, environ[i], len) == 0) &&
          (environ[i][len] == '=')) {
            olen = strlen(&environ[i][len+1]);
            if (olen >= buflen) {
                pthread_mutex_unlock(&env_mutex);
                return(ENOSPC);
            }
            strcpy(buf, &environ[i][len+1]);
            pthread_mutex_unlock(&env_mutex);
            return(0);
        }
    }
    pthread_mutex_unlock(&env_mutex);
    return(ENOENT);
}

Этот код легко понять. У меня есть вопрос, хотя. Мы никогда не звоним pthread_mutex_destroy(), что означает, что может быть утечка памяти при выходе (я думаю, она может отличаться для разных платформ).

Первое, что приходит на ум, это то, что можно использовать PTHREAD_MUTEX_INITIALIZER, Требуется ли это pthread_mutex_init() вызов? Если нет, звонить не нужно pthread_mutex_destroy(), Однако мьютекс будет нерекурсивным.

Можно написать простой класс C++, который мог бы уничтожить мьютекс в деструкторе. Тем не менее, он не подходит для тех, у кого есть только компилятор C (и, похоже, глупо использовать компилятор C++ из-за одной функции).

Другая вещь, которая приходит на ум, это специфичные для компилятора расширения, такие как __attribute__((destructor)) в GCC (и, надеюсь, лязг). Тем не менее, это не переносимо.

Можно ли избежать утечки памяти? Если да, как это можно сделать в C?

ОБНОВЛЕНИЕ Как видно из "Программирование с помощью потоков POSIX", написанного Дэвидом Бутенхофом, нам никогда не нужно уничтожать PTHREAD_MUTEX_INITIALIZER вариант. Как насчет мьютексов с другими атрибутами?

2 ответа

Ресурсы, которые остаются работоспособными после завершения процесса, не являются утечками памяти, несмотря на то, что некоторые наивные инструменты классифицируют их как таковые. Утечка памяти - это необратимый и неограниченный рост требований программы к ресурсам в течение срока ее службы, который несоразмерен фактическому рабочему набору.

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

Нет утечки памяти, потому что pthread_mutex_t переменные живут в пользовательской памяти, при выходе из процесса восстанавливается вся выделенная пользователем память. Утечки памяти происходят, когда что-то выделяет кучу памяти, например, strdup. И тогда ты не уберешься.

Если бы это было выделено как

pthread_mutex_t *foo;
....
foo =malloc(sizeof(pthread_mutex_t);

И затем не освобождается со свободным, что создает утечку памяти - если тогда foo был выделен для более новой памяти. Однако при завершении процесса ВСЕ память запрашиваемый процесс, включая кучу, восстанавливается ОС. Стивенс объясняет это в главе о процессах. Этот код не течет.

Другие вопросы по тегам