C pthread:销毁全局静态互斥

C pthread:销毁全局静态互斥,c,pthreads,reentrancy,C,Pthreads,Reentrancy,此代码取自Richard Stevens编写的第三版UNIX环境中的高级编程。这是一个如何生成可重入版本的getenv()的示例。这里演示的目的只是为了学习 /* Copyright (c) W.R.Stevens */ #include <string.h> #include <errno.h> #include <pthread.h> #include <stdlib.h> extern char **environ; pthread_mu

此代码取自Richard Stevens编写的第三版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);
}
/*版权所有(c)W.R.Stevens*/
#包括
#包括
#包括
#包括
外部字符**环境;
pthread_mutex_t env_mutex;
静态pthread_once_t init_done=pthread_once_init;
静态空隙
线程初始化(无效)
{
pthread_mutextatr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutextatr_settype(&attr,pthread_MUTEX_RECURSIVE);
pthread_mutex_init(&env_mutex,&attr);
pthread_mutexattr_destroy(&attr);
}
int
getenv_r(常量字符*名称,字符*buf,int buflen)
{
int i、len、olen;
pthread_once(&init_done,thread_init);
len=strlen(名称);
pthread_mutex_lock(&env_mutex);
对于(i=0;环境[i]!=NULL;i++){
if((strncmp(名称,环境[i],len)==0)&&
(环境){
olen=strlen(&environ[i][len+1]);
如果(olen>=buflen){
pthread_mutex_unlock(&env_mutex);
返回(EPC);
}
strcpy(buf,&environ[i][len+1]);
pthread_mutex_unlock(&env_mutex);
返回(0);
}
}
pthread_mutex_unlock(&env_mutex);
返回(eNONT);
}
这段代码很容易理解。不过我有个问题。我们从不调用
pthread\u mutex\u destroy()
,这意味着退出时可能会出现内存泄漏(我想这可能因平台而异)

首先想到的是可以使用
PTHREAD\u MUTEX\u初始值设定项
。它是否需要调用
pthread\u mutex\u init()?如果否,则无需调用
pthread\u mutex\u destroy()
。但是,互斥锁将是非递归的

<>可以编写一个简单的C++类,它可以破坏析构函数中的互斥体。但是,对于只有C编译器的人来说,这是不合适的(因为一个函数,它似乎是一个使用C++编译器的胡说)。 我想到的另一件事是特定于编译器的扩展,比如GCC中的
\uuuuuu属性((析构函数))
(当然还有clang)。但是,它是不可移植的

有可能避免内存泄漏吗?如果是,如何在C语言中实现

更新
正如David Butenhof编写的“使用POSIX线程编程”中所示,我们永远不需要销毁
PTHREAD\u MUTEX\u初始值设定项
variant。具有其他属性的互斥体如何?

没有内存泄漏,因为
pthread\u mutex\u t
变量存在于用户内存中,在进程退出时,所有用户分配的内存都会被回收。内存泄漏发生在分配堆内存时,比如strdup。 然后你不清理它

如果是这样分配的话

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

然后不释放free,这会造成内存泄漏——如果foo被分配到更多的新内存。然而,在进程终止时,包括堆在内的所有进程请求的内存都由操作系统回收。史蒂文斯在“过程”一章中对此进行了解释。该代码不会泄漏。

进程终止时仍处于活动状态的资源不是内存泄漏,尽管有些幼稚的工具将它们归类为内存泄漏。内存泄漏是程序在其生命周期内资源需求的不可逆和无限增长,与实际工作集不成比例


根据POSIX(这是您获得POSIX线程的地方),所有进程本地资源在程序终止时停止存在。没有必要显式地销毁/释放它们,在某些情况下,如您的情况,您无法安全地销毁/释放它们,您不应该尝试。

我在
pthread\u mutex\u init()期间考虑分配问题。
。如果同时存在
init()
destroy()
,我们是否应该同时调用它们呢?如果互斥锁的持续时间与整个程序的持续时间一样长,那么实际上不需要同时调用它们。但是,假设您正在创建一个链接列表,其中包含一个互斥体,并且您仅将该列表用于一个函数,然后
free()
d它。然后,您需要确保调用了
pthread\u mutex\u destroy()
,否则,如果在程序运行过程中多次调用该函数,那么这些漏洞就会累积起来。+1回答非常好。更改cargo cult“在终止进程之前必须始终明确销毁所有资源”(即使这很困难/危险,并且需要大量额外代码和测试)。