Próbuję zrozumieć implementację jądra Linuksa z listą linków i tabelą mieszania. Łącze do implementacji to here. Zrozumiałem implementację listy powiązanej. Ale jestem trochę zdezorientowany, dlaczego podwójne wskaźniki są używane w hlist (** pprev). Link do hlist to here. Rozumiem, że hlist jest używany w implementacji tablicy mieszającej, ponieważ szef listy wymaga tylko jednego wskaźnika i oszczędza miejsce. Dlaczego nie można tego zrobić za pomocą pojedynczego wskaźnika (po prostu * prev jak połączona lista)? Proszę pomóż mi.Używanie podwójnego wskaźnika w jądrze Linuksa Implementacja listy skrótów
Odpowiedz
Powodem można znaleźć w jednym z komentarzy:
547/*
548 * Double linked lists with a single pointer list head.
549 * Mostly useful for hash tables where the two pointer list head is
550 * too wasteful.
551 * You lose the ability to access the tail in O(1).
552 */
Jeśli miał * prev zamiast ** pprev i dlatego staramy się zaoszczędzić pamięć, nie zawierają w prev * głowica, wówczas nasza realizacja hlist wygląda następująco:
struct hlist_head {
struct hlist_node *first = null;
};
struct hlist_node {
struct hlist_node *next;
struct hlist_node *prev;
};
Zauważ, że wskaźnik prev
nie może wskazywać na głowie, albo head->first
(w przeciwieństwie **pprev
). To komplikuje realizację hlist, jak zobaczysz gdy wdrożymy hlist_add_before()
:
void
hlist_init(struct hlist_head *head) {
head->first = null;
}
void
hlist_add_head(struct hlist_head *head, struct hlist_node *node) {
struct hlist_node *next = head->first;
head->first = node;
node->next = next;
node->prev = NULL;
if (next) {
next->prev = node;
}
}
Zauważ, że nie ma nic do prev
wskazywać, w powyższym imeplementation z hlist_add_head()
. Więc teraz, kiedy wdrożyć hlist_add_before()
wygląda to tak:
void
hlist_add_before(struct hlist_head *head,
struct hlist_node *node,
struct hlist_next *next) {
hlist_node *prev = next->prev;
node->next = next;
node->prev = prev;
next->prev = node;
if (prev) {
prev->next = node;
} else {
head->first = node;
}
}
Zauważ, że teraz musimy przejść w head
także do hlist_add_before()
, co wymaga dodatkowego push
dyspozycję popychanie head
na stosie. Poza tym w implementacji jest dodatkowe sprawdzanie warunkowe, które dodatkowo spowalnia działanie.
Teraz spróbuj wdrożyć inne operacje hlist, z *prev
zamiast **pprev
, a przekonasz się, że twoja implementacja będzie wolniejsza niż to, co widziałeś w jądrze Linux.
- 1. Uzyskiwanie listy urządzeń sieciowych w jądrze Linuksa
- 2. Implementacja poprawnej synchronizacji między modułami w jądrze Linuksa
- 3. Implementacja wywołań systemowych/pułapek w jądrze Linuksa źródło
- 4. Jak spać w jądrze Linuksa?
- 5. Wywołanie funkcji w jądrze Linuksa
- 6. hrtimer powtarzające się zadanie w jądrze Linuksa
- 7. główna obsługa błędów strony w jądrze Linuksa
- 8. Mierzenie czasu w jądrze Linuksa 2.6
- 9. Używanie skrótów w LaTeX
- 10. Implementacja sygnałów zegarowych sprzętowych w jądrze Linux
- 11. Jak odczytać sektor za pomocą żądania bio w jądrze Linuksa
- 12. Limit linii Shebang w bashu i jądrze Linuksa
- 13. Przejście z trybu rzeczywistego do chronionego w jądrze Linuksa
- 14. Który kontekst danej funkcji jest wywoływany w jądrze Linuksa
- 15. Jak odczytać sektor za pomocą żądania biologicznego w jądrze Linuksa
- 16. Implementacja operatora konwersji dla wskaźnika
- 17. Implementacja Java stochastycznego wskaźnika dla finansów
- 18. Standardowa implementacja połączonej listy w C
- 19. Co to są przestawienia przerwań (RES)? Co to powoduje? Jak jest obsługiwany w jądrze Linuksa?
- 20. Unikaj podwójnego konkatatu w Ramdzie
- 21. Adres w jądrze
- 22. Jak linie grep zaczynają się od podwójnego ukośnika w linii poleceń Linuksa?
- 23. Używanie oryginalnego wskaźnika po ponownym przydziale?
- 24. Używanie std :: usunąć usunąć elementy wskaźnika
- 25. C#: Używanie generic stworzyć tablicę ruchy wskaźnika
- 26. Używanie const i decltype ze zmienną wskaźnika
- 27. Dlaczego jądro Linuksa # definiuje symbol jako taki?
- 28. Jądro Linuksa Czas odbioru UDP
- 29. Jak uniknąć podwójnego cudzysłowu wewnątrz podwójnego cudzysłowu?
- 30. Kernel Linuksa - Pobierz ostatni blok pamięci pisemnej
Dzięki za odpowiedź. Ale mam wątpliwości, dlaczego nie mam * prev i mam listę podwójnie połączoną. Używając tego możesz przemierzać oba sposoby. Możesz dodawać i usuwać węzły w O (1). Wykorzystana pamięć jest taka sama w obu przypadkach. Najwyraźniej czegoś tu brakuje. Czy mógłbyś wskazać mój błąd? – bala1486
Zobacz, jeśli moja opracowana odpowiedź pomaga. :) – Sudhanshu
Dziękuję bardzo ... – bala1486