web-dev-qa-db-ja.com

list_for_each_entryとlist_for_each_entry_safeについて説明する

Linuxでのlist_for_each_entryと... entry_safeループの動作を誰かが説明できますか?みたいです

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)

これらすべてのパラメーターの役割と、それらを使用してリストをトラバースする方法。

前もって感謝します

19
goodies

編集:申し訳ありませんが、それは遅くなる必要があります、私は多くのタイプミスをしました。

彼らは純粋に楽しいです! :)違いは、リストの反復中に何かを削除すると_list_for_each_entry_が壊れ、_list_for_each_entry_safe_は壊れないことです(もちろん、いくつかの追加のCPU命令を犠牲にして)。

カーネルは二重にリンクされたリスト(あなたが理解していると思います)に落ち着きましたが、list.hには単一にリンクされたリストの実装があります。あなたのリストはただです:

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

リストの「先頭」と各ノードの両方に同じ構造体が使用されていることに注意してください。リストが空の場合、ヘッドのnextおよびprevメンバーは、ヘッド自体を指し示すだけです。したがって、リストの反復は、nextと同じアドレス(停止したとき)でない限り、ヘッドのprevメンバーから開始してそのノードを呼び出すプロセスにすぎません。それ以外の場合は、for本体が呼び出され、container_of()マクロを使用して実際の構造体へのポインタを取得し、それを操作できます。次に、forの3番目のフィールドで、次の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_の単なるエイリアスです

EDIT#2

わかりましたので、コメントでのあなたの質問に答えて、私は私の答えを拡大します。この概念には、C++ STLコンテナーやC配列などに比べて奇妙な点がいくつかあるため、理解するのが難しいことを実感できますが、慣用句に慣れると、かなり自然に見えるようになります。まだ将来的には、これらの構造体、関数、マクロの定義を自分で見て、理解をまとめて質問することをお勧めします。

そのため、最初に、リストの各ノードは、_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 */
    }

}
_

今すぐ読みます!:)

17
Daniel Santos