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 был выделен для более новой памяти. Однако при завершении процесса ВСЕ память запрашиваемый процесс, включая кучу, восстанавливается ОС. Стивенс объясняет это в главе о процессах. Этот код не течет.