Объясните list_for_each_entry и list_for_each_entry_safe - программирование
Подтвердить что ты не робот

Объясните list_for_each_entry и list_for_each_entry_safe

Может кто-нибудь объяснить работу list_for_each_entry и... entry_safe loop в linux. Это похоже на

list_for_each_entry(type *cursor, struct list_head *list, member)

list_for_each_entry_safe(type *cursor, type *next, struct list_head *list,member)

Какова роль всех этих параметров и как они используются для перемещения по списку.

Спасибо в ADVANCE

4b9b3361

Ответ 1

EDIT: извините, должно быть, поздно, я сделал много опечаток.

Они просто весело!:) Разница в том, что list_for_each_entry сломается, если вы удалите что-то во время итерации списка, а list_for_each_entry_safe не будет (конечно, за счет некоторых дополнительных инструкций CPU).

Ядро оговорилось на двусвязных списках (которые, как я полагаю, вы понимаете), хотя в list.h имеется реализация с одним списком ссылок. Ваш список просто:

struct list_head {
    struct list_head *next;
    struct list_head *prev;
};

Обратите внимание, что одна и та же структура используется как для "головки" списка, так и для каждого node. Когда список пуст, члены головы next и prev просто указывают на его голову. Таким образом, повторение списка - это просто процесс запуска с элемента head next и вызов этого node, если только тот же адрес, что и prev (при остановке). В противном случае тело for вызывается, и вы можете использовать макрос container_of(), чтобы получить указатель на свою фактическую структуру и играть с ним. Затем, в третьем поле for, мы просто перейдем к следующему next.

ИЗМЕНИТЬ: крики, прошу прощения, вы попросили объяснить параметры. Хорошо, я бы проверял это прямо, если бы я был вами, а не заставлял кого-то говорить об этом. Для них я бы предложил Kernel API docs, которые, по крайней мере, существуют для библиотеки связанных списков. Я пытаюсь получить набор патчей, который добавит их для библиотеки с красно-черным деревом, но получение информации через процесс может быть довольно сложным.

Также обратите внимание: http://kernelnewbies.org/FAQ/LinkedLists

Вот пример:

struct list_head my_actual_list;
struct my_struct {
    struct list_head node;
    /* some other members */
};

/* in a function body somewhere... */
struct list_head *i;
list_for_each(i, &my_actual_list) {
    struct my_struct *obj = list_entry(i, struct my_struct, node);
    // do something with obj
}

list_entry является просто псевдонимом для container_of

РЕДАКТИРОВАТЬ № 2

ОК, поэтому, отвечая на ваш вопрос в комментариях, я собираюсь просто расширить свой ответ. Я действительно могу оценить трудности в понимании этой концепции, поскольку в ней есть несколько странных вещей в сравнении с контейнерами С++ STL, массивами C и т.д., Но как только вы привыкнете к идиомам, это будет казаться вполне естественным. Еще в будущем я действительно призываю вас начать изучать определение этих структур, функций и макросов самостоятельно и пытаться собрать вместе понимание, а затем задавать вопросы.

Итак, каждый node в вашем списке представляет собой структуру, содержащую элемент типа struct list_head, а список его self имеет тип struct list_head. Таким образом, кто является контейнером и кто является содержащимся в этом случае, просто зависит от того, как они используются, но, как правило, он будет выражаться в именах этих членов. Тип итератора - struct list_head *. Вот пример, и я заменил нормальную функцию и вызовы макросов с их эквивалентным кодом:

struct my_container {
    struct list_head list;
    int some_member;
    /* etc. */
};

struct my_obj {
    struct list_head node;
    int some_member;
    /* etc. */
};

void func() {
    struct my_container container;
    struct my_obj obj1, obj2;
    struct list_head *i;

    /* INIT_LIST_HEAD(&container.list); */
    container.list.next = &container.list;
    container.list.prev = &container.list;

    /* list_add_tail(&obj1.node); */
    container.list.prev = &obj1.node;
    obj1.node.next = &container.list;
    obj1.node.prev = &container.list;
    container.list.next = &obj1.node;

    /* list_add_tail(&obj2.node); */
    container.list.prev = &obj2.node;
    obj2.node.next = &container.list;
    obj2.node.prev = &obj1.node;
    obj1.node.next = &obj2.node;

    /* list_for_each(i, &container.list) { */
    for (i = container.list.next; i != &container.list; i = i->next) {
        struct my_obj *obj = list_entry(i, struct my_obj, node);
        /* do stuff */
    }

}

Теперь идите читать!:)