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

Fir*_*row 5 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
Run Code Online (Sandbox Code Playgroud)

$ 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目录.

Ste*_*sop 7

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

readdir_r你不分配任何东西,你给它一个dirent,但是分配你喜欢,它在填充它.因此它不保存你打电话相比,一点点努力readdir和复制DIR数据.这不是主要目的readdir_r,但是,它实际上是是使从在同一时间不同的线程,你不能做呼叫的能力readdir.

"可重入"实际意味着,该函数可以在之前的调用返回之前再次调用.在一般情况下,这可能会从不同的线程平均(这是大多数人的"线程安全"的意思),从第一次调用期间发生的一个信号的处理程序,或由于递归.但是C标准没有线程概念,所以它提到"可重入"只意味着后两者.POSIX定义"线程安全",要求这种形式重入的,此外,大多数人通过线程安全的意思的东西.

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

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


cni*_*tar 6

第一个问题

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

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

    return &dirent;
}
Run Code Online (Sandbox Code Playgroud)

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

该标准并没有强迫任何人像这样做.实现可能使用其自己的机制(也许mallocfree后来对自己).

第二个问题

"可重入"意味着当我们进入内部时readdir_r,可以再次安全地调用该函数(例如,从信号处理程序).例如,readdir不是可重入的.假设发生这种情况:

  • 你打电话readdir(dir);,它开始修改dirent
  • 在它完成之前,它被中断并且其他人调用它(来自异步上下文)
  • 它的版本修改dirent,返回和异步上下文继续进行
  • 您的版本返回.什么dirent包含?

可重入的功能是天赐之物,它们始终可以安全地呼叫.


mah*_*mah 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()将使用调用者提供的已分配空间,让多个线程独立运行.

  • 重入和线程安全实际上是完全不同的.`malloc`是线程安全的但不是可重入的.相反,任何使用静态存储但在进入/退出时备份和恢复自动存储中的静态数据的函数都是可重入的,但不太可能是线程安全的. (2认同)