LINUX.ORG.RU

[C] Связные списки: реализация glib VS реализация linux kernel

 


0

2

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

glib:

struct GList {
  gpointer data;
  GList *next;
  GList *prev;
};

next и prev указывают на такой же GList

linux:

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

struct my_cool_list{
	struct list_head list; /* kernel's list structure */
	int my_cool_data;
	void* my_cool_void;
};

То, что вижу я:

1. Реализация в linux требует на sizeof(void *)*N байт меньше, чем реализация в glib, где N - количество элементов в списке.

Why so?

glib = N * { sizeof(next_ptr) + sizeof(prev_ptr) + sizeof(data_ptr) + sizeof(data_struct) }

linux = N * { sizeof(data_struct) + sizeof(next_ptr) + sizeof(prev_ptr) }

То есть, нет N штук data_ptr.

2. Мне кажется, модель списков в glib более интуитивно понятная.

Плюс, в linux list_head структура сама определяет, в каких списках она может хранится. Если я захочу добавить возможность вносить структуру в список, у меня есть 2 варианта:

а) изменить код структуры и добавить туда еще один list_head;

б) написать структуру-обертку и использовать уже ее.

То есть, код получается зависимым от того, что сделал разработчик. В linux такое можно легко использовать, поскольку сорцы открыты, либо закрыты полностью (есть только unmodifiable headers).

Опять же, неудобно каждый раз писать структуру обертку

struct my_struct {
  int a;
  struct list_head list1;
};

struct my_struct_add {
  struct my_struct datal
  struct list_head list2;
};

для добавления возможности вставлять структуру в списки.

Гораздо проще в данном плане использовать модель GLib, где _любой_ объект может быть добавлен в список.

3. Реализация list_head оперирует сдвигом для определения указателя на структуру по указателю на list_head.

void *mystruct_ptr = mylist_ptr - &(((struct mystruct *)0)->mylist_head);

Насколько это портабельно между различными компиляторами?

Тема интересная, посему - lets discuss begin!

★★

Ответ на: комментарий от AIv

Списки бывают ОДНОсвязные и ДВУХсвязные, НЕсвязных списков не бывает;-)

QList с тобой не согласен. Но вообще ты прав ;)

const86 ★★★★★
()
Ответ на: комментарий от const86

QList нихрена не список, а являет собой массив указателей на данные и, соответственно, самые данные где-то в памяти.

Chaser_Andrey ★★★★★
()
Ответ на: комментарий от AIv

Не. Массив - это массив.

Даже не знаю что сказать. Против такой железной аргументации не попрешь. Да это и не важно. Терминологический срач, самый бесполезный срач.

Вот тут есть некоторое видение на иерархию в терминах и что чем является: http://ru.wikipedia.org/wiki/Список_структур_данных. Там есть отдельные понятия «список» и «связный список» и можно посмотреть положение термина «массив» в этой иерархии.

Можно сказать, что Википедии нельзя верить в этом (конкретном) вопросе. Не буду спорить. Но видно, что термин «связный список» достаточно употребителен, а значит ничего зазорного в его использовании нет.

//С нетерпением жду от Alv ссылки на (более или менее) авторитетные ресурсы, доказывающие обратную точку зрения.

pathfinder ★★★★
()
Ответ на: комментарий от bk_

Короче, самый главный минус GList здесь - удвоенное количество malloc-ов при использовании кучи (что обычно и делается), что при большом числе элементов дает нехилый оверхед.

g_list_alloc по-умолчанию кучу не использует. Так что malloc обычно один.

k_andy ★★★
()
Ответ на: комментарий от bk_

>удвоенное количество malloc-ов при использовании кучи

У GLib'а свой особенный маллок, основанный на SLAB из Linux-ядра, и специально разработанный для выделения большого количества мелких объектво.

elverion
()
Ответ на: комментарий от AIv

«Список абитуриентов», ListView из графических тулкитов, QList, и т.д.

elverion
()
Ответ на: комментарий от Chaser_Andrey

>QList нихрена не список

Что же это? Дерево? Может быть вообще граф?

elverion
()
Ответ на: комментарий от pathfinder

Опа, а я таки неправ... Все авторы как один используют устоявшийся термин «связанный список» (видимо калька с английского linked list), Кнут вводит термин «линейный список» куда лезет и массив в т.ч. Термин «несвязанный список» используется крайне редко, но таки встречается.

С другой стороны, все знакомые с фундаментальным програмистким образованием у кого я спрашивал, утверждали что несвязных списков не бывает а связный список звучит странно и режет ухо.

ИМНО со временем «связный список» уйдет в прошлое, во всяком случае видно как это происходит в умах программистов-практиков. Но пока...

Приношу свои извинения.

AIv ★★★★★
()
Ответ на: комментарий от elverion

У GLib'а свой особенный маллок, основанный на SLAB из Linux-ядра, и специально разработанный для выделения большого количества мелких объектво.

Ты частично прав. У глиба маллок по умолчанию стандартный системный:

static GMemVTable glib_mem_vtable = {
  standard_malloc,
  standard_realloc,
  standard_free,
  standard_calloc,
  standard_try_malloc,
  standard_try_realloc,
};

И переопределение этой таблицы не делается из самого глиба не делается (если не компилить глиб с разными отладочными опциями).

А выделение памяти в списках правда делается через GSlice. Попытался читать код g_slice_alloc() - сходу нихрена не понял, но идея правда через SLAB.

bk_ ★★
() автор топика
Ответ на: комментарий от anonymous

Тю...

допустим, у тебя есть два указателя:

struct GList *ptr1;
struct list_head *ptr2;

чтобы добраться до данных первого элемента надо (преобразование данных опущено):

int data1 = ptr1->data->data1;
int data2 = ptr2->next->data2;

А всё почему? а потому, что ptr2 - это указатель на заголовок списка. Который по сути не обязан быть частью какой-либо структуры, но для целостности списка и для правильной работы list_* функций он должен быть создан и инициирован!

xydo ★★
()
Ответ на: комментарий от xydo

вообще ядерные списки можно использовать только тогда, когда поймешь, как они работают. иначе seg.fault-ы гарантированны. :)

xydo ★★
()
Ответ на: комментарий от bk_

Это код, формирующий иерархию SEH-фреймов которая будет раскручиваться при возникновении исключения.

//x4da

anonymous
()
Ответ на: комментарий от anonymous

Я это понял прекрасно, но причем здесь стек и связные списки а-ля list_head?

bk_ ★★
() автор топика
Ответ на: комментарий от const86

>> Списки бывают ОДНОсвязные и ДВУХсвязные, НЕсвязных списков не бывает;-)

QList с тобой не согласен. Но вообще ты прав ;)


Вообще-то он не прав. А теперь вместе с ним и ты.


http://www.linux.org.ru/jump-message.jsp?msgid=6347842&cid=6360121

LamerOk ★★★★★
()
Ответ на: комментарий от xydo

> чтобы добраться до данных первого элемента надо

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

anonymous
()
Ответ на: комментарий от LamerOk

>>> Списки бывают ОДНОсвязные и ДВУХсвязные, НЕсвязных списков не бывает;-)

QList с тобой не согласен. Но вообще ты прав ;)

Вообще-то он не прав. А теперь вместе с ним и ты.

Односвязные и двусвязные списки, массив, двоичное дерево - это всё конкретные структуры данных. Просто список - это по сути интерфейс любой структуры данных, позволяющей представить последовательность. Все 4 выше перечисленных структуры под него подходят, можно и другие нафантазировать. Пожалуй, хешмап не сойдёт за список. Вот поэтому не стоит валить в кучу списки и двухвязные списки.

Про QList я вспомнил к тому, что некоторые его методы обещают больше, чем может какой попало список. Например, доступ по индексу за постоянное время.

const86 ★★★★★
()
Ответ на: комментарий от const86

> Вот поэтому не стоит валить в кучу списки и двухвязные списки.

Еще точнее - не стоит валить в кучу списки и связные списки. Скольки связные - дело десятое. И именно в этом заключался мой поинт.

LamerOk ★★★★★
()
Ответ на: комментарий от anonymous

>никто не мешает сделать его частью структуры тоже
частью другой структуры - никто не мешает.
той же самой - увы, нельзя (только если через static, но это уже си-плюс-плюзм).

xydo ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.