почему в справочной странице readdir C говорится, что не нужно вызывать free для статической распределенной структуры результатов - PullRequest
5 голосов
/ 23 августа 2011

$ 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 и возвращает NULL в * результате.

Меня смущает, что это означает, что я применяю эту функцию для сбора динамически размещенного массива указателей на структуры с данными о записях каталога, и мне интересно, могу ли я динамически распределить структуры directnt и установить указатели на них. но эта строка говорит о том, что результат никогда не должен вызываться free, поэтому мне интересно, должен ли я выделить отдельную структуру dirent, которая будет частью списка, и memcpy над возвращаемым результатом.

Меня также смущает терминология "май" на приведенной выше странице руководства. Означает ли это, что иногда он статически размещен, а иногда нет.

Я знаком (смутно) с тем, что означают статические переменные в C, но не уверен насчет всех правил и возможных ошибок вокруг них. поскольку я хочу передать директивные структуры, находящиеся в каталоге, я бы предпочел, чтобы он был динамически размещен. это то, что readdir_r для? или двойной указатель будет указывать на другую статически распределенную структуру dirent?

и я не совсем уверен, что означает в этом контексте повторное поступление для readdir_r. я понимаю ренетрант только из сопрограмм схемы, которые я не уверен, как это применимо к чтению каталогов Unix.

Ответы [ 3 ]

7 голосов
/ 23 августа 2011

Структура может быть статически размещена, она может быть локальной для потока, она может быть динамически размещена.Это до реализации.Но несмотря ни на что, вы не должны освобождать его, поэтому вы не должны его освобождать.

readdir_r ничего не выделяет для вас, вы даете ему dirent, выделяемому как хотите,и он заполняет его. Поэтому он экономит вам немного усилий по сравнению с вызовом readdir и копированием данных dir.Это не главная цель readdir_r, но на самом деле для - это возможность совершать вызовы из разных потоков одновременно, чего нельзя сделать с readdir.

Что на самом деле означает «реентерабельный», так это то, что функция может быть вызвана снова до того, как будет возвращен предыдущий вызов.В общем, это может означать из другого потока (что большинство людей называют «потокобезопасным»), из обработчика сигнала, который произошел во время первого вызова, или из-за рекурсии.Но в стандарте C отсутствует понятие потоков, поэтому в нем упоминается «входящий», что означает только последние два.Posix определяет «потокобезопасность», чтобы требовать эту форму повторяемости и , кроме того, то, что большинство людей подразумевает под многопоточностью.

В Posix каждая функция должна быть поточной.-safe требуется для повторного входа, а readdir_r должен быть потокобезопасным.Я думаю, что вход в более слабом смысле не имеет отношения к readdir_r, поскольку он не вызывает никакого пользовательского кода, который может привести к рекурсии, и он не безопасен для асинхронного сигнала, поэтому его также нельзя вызывать из обработчика сигнала.

Осторожно, потому что, когда некоторые люди (программисты на Java) говорят «поточно-ориентированные», они имеют в виду, что функция может быть вызвана разными потоками с одинаковыми аргументами в одно и то же время и будетиспользуйте замки для правильной работы.API-интерфейсы Posix не подразумевают поточно-ориентированный подход, а лишь означают, что функцию можно вызывать для разных данных одновременно.Любые глобальные данные, которые использует функция, защищены блокировками или иным образом, но аргументы не обязательно должны быть.

6 голосов
/ 23 августа 2011

Правило здесь очень простое - вы можете сделать копию данных, возвращаемых 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. - это означает, что вы не можете рассчитывать на то, как с ним будут управлять, но он будет управляться за вас. Детали могут варьироваться от одной системы к другой.

Reentrant означает потокобезопасный. readdir () использует статическую запись, что делает использование нескольких потоков небезопасным, как если бы каждый из них контролировал процесс множественных вызовов. readdir_r () будет использовать выделенное пространство, предоставленное вызывающей стороной, позволяя нескольким потокам действовать независимо.

6 голосов
/ 23 августа 2011

Первый вопрос

Это означает, что readdir может иметь что-то вроде этого:

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

    return &dirent;
}

Очевидно, что было бы незаконно освобождать его (, поскольку вы не получили его через malloc).

Стандарт никого не заставляет делать это так. Реализация может использовать свой собственный механизм (возможно, malloc и free позже самостоятельно).

Второй вопрос

«Reentrant» означает, что пока мы находимся внутри readdir_r, , функцию можно безопасно вызывать снова (например, из обработчика сигнала). Например, readdir не является реентерабельным. Предположим, это происходит:

  • Вы звоните readdir(dir);, и он начинает изменять dirent
  • ДО того, как это сделано, оно прерывается, и кто-то еще вызывает его (из асинхронного контекста)
  • Его версия изменяет dirent, возвращает, и асинхронный контекст продолжает свой путь
  • Ваша версия возвращается. Что содержится в dirent?

Reentrant функции - находка, их всегда безопасно вызывать.

...