2013-04-26 4 views
16

समझाएं कोई भी list_for_each_entry के काम को समझा सकता है और ... linux में entry_safe loop। यहlist_for_each_entry और list_for_each_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)

है क्या इन सभी मापदंडों की भूमिका कर रहे हैं और कैसे वे सूची पार करने के लिए उपयोग किया जाता है।

अग्रिम धन्यवाद

+1

मैं सुझाव है कि आप किताब लिनक्स कर्नेल को समझने पढ़ें। – stdcall

+0

आपके सुझाव के लिए धन्यवाद, इस पुस्तक में सूची से संबंधित अच्छी सामग्री है .. – goodies

उत्तर

12

संपादित करें: माफ करना, यह देर से, मैं लिखने की त्रुटियों की एक बहुत कुछ कर दिया है होना चाहिए।

वे शुद्ध मजाक हैं! :) अंतर यह है कि list_for_each_entry तोड़ देगा यदि आप सूची को पुन: करते समय कुछ हटाते हैं और list_for_each_entry_safe नहीं होगा (बेशक, कुछ अतिरिक्त CPU निर्देशों की कीमत पर)।

कर्नेल दोगुनी-लिंक्ड सूचियों (जो मुझे लगता है कि आप समझते हैं) पर बस गए हैं, हालांकि सूची में एक सिंगल लिंक्ड सूची कार्यान्वयन है। अपनी सूची बस है:

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

नोट है कि एक ही struct दोनों सूची के "सिर" के साथ-साथ प्रत्येक नोड के लिए प्रयोग किया जाता है। जब सूची खाली होती है, तो सिर का next और prev सदस्य केवल अपने सिर को इंगित करते हैं। इस प्रकार, सूची को पुन: सक्रिय करना केवल next सदस्य से शुरू करने की प्रक्रिया है और एक नोड को कॉल करना, जब तक कि यह prev (जब आप रुकें) के समान पता हो। अन्यथा, आपके for शरीर को बुलाया जाता है और आप container_of() मैक्रो का उपयोग अपने वास्तविक संरचना में पॉइंटर प्राप्त करने और इसके साथ खेलने के लिए कर सकते हैं। फिर, for के तीसरे क्षेत्र में, हम बस अगले next पर जाएं।

संपादित करें: व्हाउप्स, मैं क्षमा चाहता हूं, आपने पैरामीटर की व्याख्या के लिए कहा था। खैर, अगर मैं इसके लिए किसी के शब्द लेने के बजाए आप सीधे थे तो मैं इसे सीधे देखता हूं। उन लोगों के लिए, मैं Kernel API docs स्वयं का सुझाव दूंगा, जो कम से कम लिंक्ड सूची लाइब्रेरी के लिए मौजूद है। मैं एक पैच सेट प्राप्त करने की कोशिश कर रहा हूं जो उन्हें लाल-काले पेड़ पुस्तकालय के साथ भी जोड़ देगा, लेकिन सामान भरना काफी प्रक्रिया हो सकता है।

नोट के

इसके अलावा:

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

ठीक एक उपनाम है जवाब में इतना: http://kernelnewbies.org/FAQ/LinkedLists

यहां एक त्वरित उदाहरण है टिप्पणियों में आपके प्रश्न के लिए, मैं बस अपना जवाब विस्तारित करने जा रहा हूं। मैं वास्तव में इस अवधारणा को समझने में कठिनाई की सराहना कर सकता हूं क्योंकि सी ++ एसटीएल कंटेनर, सी सरणी आदि की तुलना में इसमें कुछ अजीब चीजें हैं, लेकिन एक बार जब आप मुहावरे के आदी हो जाते हैं, तो यह काफी स्वाभाविक प्रतीत होता है। अभी भी भविष्य में, मैं आपको सचमुच आग्रह करता हूं कि आप इन structs के लिए परिभाषा को देखना शुरू करें, & फ़ंक्शन स्वयं को मैक्रोज़ करें और एक साथ समझने की कोशिश कर रहे हैं, फिर प्रश्न पूछें।

तो सबसे पहले बंद, अपनी सूची में प्रत्येक नोड एक struct है कि प्रकार struct list_head के एक सदस्य और सूची अपने स्वयं प्रकार 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 */ 
    } 

} 

Now go read! :)

+0

मैं आपको प्राप्त कर रहा हूं लेकिन मैं जानना चाहता हूं कि वे कैसे संबंधित हैं और यह इटेटरेटर किस स्थिति की जांच करेगा .. उदाहरण के लिए यदि हम लूप के लिए उपयोग करते हैं तो ** (int i = 0; i <= 5; i ++) ** इस तरह यह पुनरावर्तक अगली बार फिर से चालू होगा, किस आधार पर यह इसके अगले तत्व की जांच करेगा .. – goodies

+1

आह हाँ, आप देखेंगे कि मैंने चर नाम का उपयोग किया है 'मैं', क्योंकि मैं इसे अपना इटरेटर कह रहा हूं। कुछ लोग परिवर्तनीय नाम 'pos' का उपयोग करते हैं, क्योंकि यह सूची में "स्थिति" है, लेकिन मैं "इटरेटर" सम्मेलन के साथ रहना पसंद करता हूं। यह लंबा है, इसलिए मैं अपना जवाब विस्तारित करने जा रहा हूं। –

संबंधित मुद्दे