为什么C readdir手册页说不在静态分配结果结构上调用free

时间:2011-08-23 09:23:27

标签: c unix dirent.h

$ uname -a

Linux crowsnest 2.6.32-28-generic #55-Ubuntu SMP Mon Jan 10 23:42:43 UTC 2011 x86_64 GNU/Linux

$ man readdir:

  

说明

     

readdir()函数返回一个指向dirent结构的指针,该结构表示指向的目录流中的下一个目录条目。          dirp ......

     

... [剪断] ...

     

readdir_r()函数是readdir()的可重入版本...

     

... [剪断] ...

     

返回值

     

成功时,readdir()返回指向dirent结构的指针。 (此结构可以静态分配;不要尝试释放(3)它。)如果到达目录流的末尾,则返回NULL并且不更改errno。如果发生错误,则返回NULL并正确设置errno。

     

readdir_r()函数成功返回0。出错时,它返回正误差编号。如果到达目录流的末尾,则readdir_r()返回0,并在* result中返回NULL。

我对这意味着什么感到困惑,我的这个函数的应用是收集动态分配的结构指针数组,其中包含有关目录条目的数据,我想知道我是否可以动态分配dirent结构并设置指向他们的指针。但这一行接着说结果永远不应该被free释放,所以我想知道我是否应该分配一个单独的dirent结构,它将成为列表的一部分并将其存储在返回的结果中。

我也对上面手册页中“may”的术语感到困惑。这是否意味着它被静态分配,有时它不是。

我很熟悉(含糊地)静态变量在C中的意思,但不确定所有规则和可能的问题。因为我想传递目录中的dirent结构,我宁愿它是动态分配的。这是readdir_r的用途吗?或者将双指针设置为指向另一个静态分配的dirent结构?

并且我不完全确定在这个上下文中readdir_r的重入意味着什么。我对renetrant的理解只来自方案协同程序,我不确定它如何适用于读取unix目录。

3 个答案:

答案 0 :(得分:7)

结构可能是静态分配的,可能是线程本地的,也可能是动态分配的。这取决于实施。但无论如何,这都不是你的自由,这就是为什么你不能释放它。

readdir_r没有为你分配任何东西,你给它一个dirent,分配你喜欢的东西,并填充它。因此,与调用相比,它确实可以省去一些努力readdir并复制dir数据。这不是readdir_r的主要目的,但它实际上 的能力是能够同时从不同的线程进行调用,这是readdir无法做到的。 }。

“reentrant”实际意味着什么,该函数可以在之前的调用返回之前再次调用。一般来说,这可能意味着来自不同的线程(这是大多数人所说的“线程安全”),来自第一次调用期间发生的信号的处理程序,或者是由于递归。但是C标准没有线程概念,所以它提到“可重入”只意味着后两者。 Posix定义了“线程安全”来要求这种形式的重入,此外,大多数人都认为是线程安全的。

在Posix中,要求线程安全的每个函数都需要是可重入的,并且readdir_r必须是线程安全的。我认为较弱的意义上的重入与readdir_r无关,因为它不会调用任何可能导致递归的用户代码,并且它不是异步信号安全的,因此不能从信号处理程序中调用它。

请注意,因为当某些人(Java程序员)说“线程安全”时,他们意味着该函数可以同时由不同的线程在相同的参数上调用,并将使用锁定正常工作。 Posix API并不意味着线程安全,它们只意味着可以同时在不同的数据上调用该函数。函数使用的任何全局数据都受锁或其他方式的保护,但参数不一定是。

答案 1 :(得分:6)

第一个问题

这意味着readdir可以有这样的东西:

struct dirent *
readdir(DIR *dirp)
{
    static struct dirent;
    /* Do stuff. */

    return &dirent;
}

显然,释放它是违法的(,因为你没有通过malloc 获得它。)

标准并没有强迫任何人像这样做。实现可以使用自己的机制(稍后可能mallocfree)。

第二个问题

“可重入”意味着当我们在readdir_r内时,可以再次安全地调用该函数(例如来自信号处理程序)。例如,readdir不可重入。假设发生这种情况:

  • 您致电readdir(dir);并开始修改dirent
  • 在它完成之前,它被中断并且其他人称之为(来自异步上下文)
  • 其版本修改dirent ,返回并且异步上下文继续运行
  • 您的版本返回。 dirent包含哪些内容?

Reentrant函数是天赐之物,它们总是可以安全地调用。

答案 2 :(得分:6)

此处的规则非常简单 - 您可以自由复制数据readdir()返回,但是您不拥有将数据放入的缓冲区,因此您无法采取建议您的操作做。 (即,将数据复制到您自己的缓冲区;不要将指针存储在readdir拥有的缓冲区中。)

so I'm wondering if I should allocate a seperate dirent struct which will be part of the list and memcpy it over the returned result - 这正是你应该做的。

I'm also confused by the terminology of "may" in the above man page. does this mean that somtimes it's statically allocated, and sometimes it's not. - 这意味着您不能指望它将如何管理,但它将为您管理。细节可能因系统而异。

可重入意味着线程安全。 readdir()使用静态条目,使多个线程使用它们并不安全,就好像它们各自控制多次调用进程一样。 readdir_r()将使用调用者提供的已分配空间,让多个线程独立运行。