Здравствуйте, Erop, Вы писали:
E>Не секрет. Фишка в том, что аллокация -- это очень дорого. А буфер на стеке -- нет. Это одна из популярных техник, которая в С++ позволяет обойтись без alloca, без потери эффективности. E>Сценарий использования такой. Пусть у тебя есть какая-то задача, требующая буфера, который обычно легко помещается на стеке, но иногда может быть сколь угодно большим. Например тебе надо обработать по одной строки в каком-нибудь текстовом файле. Ты заводишь CAutoBuffer с таким параметром, чтобы в обычном случае данные поместились в его внутренний буфер. И при использовании, говоришь ему какого размера нужен буфер и получаешь требуемое. E>В результате, в обычных случаях, когда данных мало (строки в файле нормальной длины, не больше 4К, например) ты работаешь на стеке и не тратишь время на аллокации, а в редких случаях, когда данных много, работаешь на буфере, выделенном на куче. При этом, это всё происходит прозрачным для клиентского кода образом, за исключением того, что в первом режиме экземпляр CAutoBuffer содержит внутри себя указатель на себя же.
Познакомься с VirtualAlloc, MEM_RESERVE, MEM_COMMIT, почитай Рихтера. Эта задача решается куда более элегантным способом, без единого копирования и с теми же требованиями. У тебя же периодически будет выполняться копирование памяти при расширении буфера.
Прозрачность для клиентского кода можно обеспечить, если завернуть это все в класс.
Да, это не переносимо. Но меня переносимость интересует мало, а в пределах Windows — это самое эффективное решение.
Я это упражнение студентам даю, причем в более сложном виде. Хочешь попробовать ?
PD>>>>Структура, лежащая не в одном куске. offsetof плачет горючими слезами. E>>>Почему обязательно именно struct? Данные могут иметь и более замысловатую структуру
E>>>Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа... E>Это просто омонимия. Имелась в виду структура данных.
А если имелась в виду произвольная структура данных (что угодно то есть), то какой смысл говорить о том, что она не лежит в одном куске памяти ?
E>>>Ну а писать список в расчёте на привязку именно к Win32 -- это, IMHO, безумие. PD>>Уф... E>Думаешь не безумие?
Здравствуйте, Erop, Вы писали:
E>Советую поэкспериментировать на сегментной памяти E>Конечно, если у тебя вся структура лежит в ОДНОМ куске памяти, то можно юзать смещения, а вот если не вся или не в одном, то опа...
Ну давай.
struct ANYSTRUCT
{
// что хочешь
};
union ANYUNION
{
struct ANYSTRUCT as;
char arr[на sizeof(ANYSTRUCT)];
};
Ну и как ? Массив arr лежит непрерывно или нет ? Пройти его p++ можно или нет ? А если все же можно, значит, он лежит непрерывно. Но тогда и ANYSTRUCT лежит тоже непрерывно, иначе что это будет за union ?
И ни слова тут нет о том, как это реализовано. Хоть с плоской моделью, хоть с сегментной.
Другое дело, что непрерывность эта будет реализовываться довольно хитрым способом. В DOS придется в общем случае использовать huge-указатели, и непрерывность будет не в формате seg:ofs, а в формате физического адреса == 16*seg + ofs. В защищенном режиме 286 непрерывность будет обеспечена с помощью тех же huge-указателей, но механизм ее реализации будет намного сложнее (несколько записей в GTT/LDT, таких, что непрерывно меняется у них база).
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Познакомься с VirtualAlloc, MEM_RESERVE, MEM_COMMIT, почитай Рихтера. Эта задача решается куда более элегантным способом, без единого копирования и с теми же требованиями. У тебя же периодически будет выполняться копирование памяти при расширении буфера.
1) Представь себе я это всё знаю
2) Копирование, если ты заранее знаешь размер буфера, будет не нужно ни разу
3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле?
PD>Прозрачность для клиентского кода можно обеспечить, если завернуть это все в класс. PD>Да, это не переносимо. Но меня переносимость интересует мало, а в пределах Windows — это самое эффективное решение.
Ну тебя не интересует, а других интересует Я же тебе предлагал пояснить, что ты обсуждаешь списки заточенные только под винду?
PD>Я это упражнение студентам даю, причем в более сложном виде. Хочешь попробовать ?
Упражние можешь опубликовать, если хочешь
PD>А если имелась в виду произвольная структура данных (что угодно то есть), то какой смысл говорить о том, что она не лежит в одном куске памяти ?
Ну так мы списки любых объектов обсуждали вроде?
PD>Думаю, что ты так ничего и не понял.
Ну так уж объясняете, товарищ преподаватель
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>Познакомься с VirtualAlloc, MEM_RESERVE, MEM_COMMIT, почитай Рихтера. Эта задача решается куда более элегантным способом, без единого копирования и с теми же требованиями. У тебя же периодически будет выполняться копирование памяти при расширении буфера. E>1) Представь себе я это всё знаю
Похоже. что не очень, см. ниже.
E>2) Копирование, если ты заранее знаешь размер буфера, будет не нужно ни разу
А с VirtualAlloc оно не будет нужно ни разу, даже если ты и не знаешь размер буфера, а знаешь только заведомо врехнюю границу.
E>3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле?
Нет, по 4K. Не рутай коммитирование и резервирование. А насчет std::string — я не про него, а про твой CAutoBuffer говорю. Для std::string — да, не очень подходит.
PD>>Я это упражнение студентам даю, причем в более сложном виде. Хочешь попробовать ? E>Упражние можешь опубликовать, если хочешь
Решать будешь ? Если будешь — опубликую после 1 сентября, задачи на сервере, который сейчас выключен.
PD>>А если имелась в виду произвольная структура данных (что угодно то есть), то какой смысл говорить о том, что она не лежит в одном куске памяти ? E>Ну так мы списки любых объектов обсуждали вроде?
Не юли. Ты уже на структуры перекинулся и начал мне заявлять, что, мол, они могут не непрерывно лежать. А когда я тебя на этом поймал, заявил, что структуры в твоем понимании — и не struct вовсе, а некие произвольные структуры данных. Перечитай свои постинги.
PD>>Думаю, что ты так ничего и не понял. E>Ну так уж объясняете, товарищ преподаватель
Что поделать, порой мне попадаются студенты, амбиции которых явно превышают их амуницию
Здравствуйте, Pavel Dvorkin, Вы писали:
E>>2) Копирование, если ты заранее знаешь размер буфера, будет не нужно ни разу PD>А с VirtualAlloc оно не будет нужно ни разу, даже если ты и не знаешь размер буфера, а знаешь только заведомо врехнюю границу.
Зато будет нужен сам по себе VirtualAlloc, далеко не дешёвый, прямо скажем
E>>3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле? PD>Нет, по 4K. Не рутай коммитирование и резервирование.
Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится.
E>>А насчет std::string — я не про него, а про твой CAutoBuffer говорю. Для std::string — да, не очень подходит.
CAutoBuffer -- это просто std::string очищенный от работы со строкой. Просто сам по себе механизм аллокации буфера. std::string можно написать поверх него, например.
Почему VirtualAlloc сюда никак не подходит?
Да потому, что он вообще не ту задачу решает. Нам (например в строке) надо не переаллокировать буфер уметь, а быстро его получать под нужный размер. Это основная операция.
Кроме того, VirtualAlloc вообще штука неудобная, потому, что не массштабируемая. Конечно, когда у тебя в программе есть какой-то *самый главный буффер", то можно зарезервировать под него 500 метров и коммитить понемножку. Но, если у тебя есть много буферов, в каких-то классах-данных, например, в строках или в небольших картинках или ещё в чём-то рассеянном по всей программе. И у тебя любой экземпляр может захотеть аллокировать большой буфер, но почти всем при этом хватает маленького, то подход с VirtualAlloc вообще неприменим. Просто потому, что адресного пространства не хватит на 32-битной ОС...
На всяк. случай напомню нить дискуссии.
Обсуждалось как наждо делать односвязанные списки. Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов. Я возразил тебе, что есть много довольно классов, которые не позволяют себя просто так бинарно обменивать. Ты привёл довод, что эти классы являются неинтересными редкими частными случаями, а я привёл тебе пример такого класса, который к редким и неинтересным отнести сложно -- это std::string.
Вот давай сконцентрируемся на конкретном примере. Типа мы хотим разработать класс, который работает с каким-то данными переменной длины, с картинками или строками или ещё чем-то похожим. Для определённости пусть будут строки, но давай не углубляться собственно в строковую специфику и сконцентрируемся на работе с памятью. Вот мы хотим разработать такую строку, чтобы в случае коротких строк не тратить время на аллокацию буфера.
Я знаю два популярных эффективных подхода.
1) иметь пул коротких буферов, и брать строки оттуда. Эффективно, но не в многопоточном окружении, так как на работе с пулом нужна синхронизация.
Зато органично смотрится с COW, который тоже плохо совместим с многопоточнм окружением.
2) Иметь буфер в экземпляре, а если строка в такой буффер не помещается, то аллокировать буфер на аллокаторе. При копировании строки данные и буфер копируют. Имеем наклодные расходы на копирование строк, зато не имеем тормозов в многопоточном окружении. Во всяком случае на коротких строках, где удельный вес тормозов на одну букву получается особенно большим.
PD>Решать будешь ? Если будешь — опубликую после 1 сентября, задачи на сервере, который сейчас выключен.
Ну я люблю решать интересные задачи. Как и все посетители этого раздела форума, я надеюсь.
PD>Не юли. Ты уже на структуры перекинулся и начал мне заявлять, что, мол, они могут не непрерывно лежать. А когда я тебя на этом поймал, заявил, что структуры в твоем понимании — и не struct вовсе, а некие произвольные структуры данных. Перечитай свои постинги.
Да не волнуйся. Я знаю и как структуры лежат и как аллокатры работают и много чего ещё. Я правда имел в виду структуру данных. Если ты знаешь какое-то другое слово, которое позволяло бы избежать такой путаницы, то сообщи его. В любом случае это всё не важно, в контексте обсуждения списков, так я назвал структуры данных или нет. Я-то не преподаватель и грамотно выражаться не обязан
PD>Что поделать, порой мне попадаются студенты, амбиции которых явно превышают их амуницию
Какую такую амуницию? У меня тут жарко и я за компом в одних трусах
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>А с VirtualAlloc оно не будет нужно ни разу, даже если ты и не знаешь размер буфера, а знаешь только заведомо врехнюю границу. E>Зато будет нужен сам по себе VirtualAlloc, далеко не дешёвый, прямо скажем
Далеко не такой дорогой, как ты думаешь. Проверял.
E>>>3) Как ты себе представляешь std::string на VirtualAlloc? Там память по 64К мотают на самом деле? PD>>Нет, по 4K. Не рутай коммитирование и резервирование. E>Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится.
Нет.
lpAddress
The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
E>>>А насчет std::string — я не про него, а про твой CAutoBuffer говорю. Для std::string — да, не очень подходит. E>CAutoBuffer -- это просто std::string очищенный от работы со строкой. Просто сам по себе механизм аллокации буфера. std::string можно написать поверх него, например. E>Почему VirtualAlloc сюда никак не подходит? E>Да потому, что он вообще не ту задачу решает. Нам (например в строке) надо не переаллокировать буфер уметь, а быстро его получать под нужный размер. Это основная операция. E>Кроме того, VirtualAlloc вообще штука неудобная, потому, что не массштабируемая. Конечно, когда у тебя в программе есть какой-то *самый главный буффер", то можно зарезервировать под него 500 метров и коммитить понемножку. Но, если у тебя есть много буферов, в каких-то классах-данных, например, в строках или в небольших картинках или ещё в чём-то рассеянном по всей программе. И у тебя любой экземпляр может захотеть аллокировать большой буфер, но почти всем при этом хватает маленького, то подход с VirtualAlloc вообще неприменим. Просто потому, что адресного пространства не хватит на 32-битной ОС...
Все верно.
E>На всяк. случай напомню нить дискуссии. E>Обсуждалось как наждо делать односвязанные списки.
Не делать, а уничтожать с конца.
>Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов.
Опять же не делать, а только уничтожать.
>Я возразил тебе, что есть много довольно классов, которые не позволяют себя просто так бинарно обменивать. Ты привёл довод, что эти классы являются неинтересными редкими частными случаями, а я привёл тебе пример такого класса, который к редким и неинтересным отнести сложно -- это std::string. E>Вот давай сконцентрируемся на конкретном примере. Типа мы хотим разработать класс, который работает с каким-то данными переменной длины, с картинками или строками или ещё чем-то похожим. Для определённости пусть будут строки, но давай не углубляться собственно в строковую специфику и сконцентрируемся на работе с памятью. Вот мы хотим разработать такую строку, чтобы в случае коротких строк не тратить время на аллокацию буфера. E>Я знаю два популярных эффективных подхода. E>1) иметь пул коротких буферов, и брать строки оттуда. Эффективно, но не в многопоточном окружении, так как на работе с пулом нужна синхронизация. E>Зато органично смотрится с COW, который тоже плохо совместим с многопоточнм окружением. E>2) Иметь буфер в экземпляре, а если строка в такой буффер не помещается, то аллокировать буфер на аллокаторе. При копировании строки данные и буфер копируют. Имеем наклодные расходы на копирование строк, зато не имеем тормозов в многопоточном окружении. Во всяком случае на коротких строках, где удельный вес тормозов на одну букву получается особенно большим.
Резюме простое — для решения разных задач нужны разные методы, и с этим никто не спорит. Твоя идея насчет буфера в экземпляре прокатит со страшной силой, если тебе придется в большинстве случае все же в итоге аллокировать буфер на стороне. Ничего кроме понапрасну потраченной памяти не будет, плюс копирование. В других случаях это может оказаться уместным.
PD>>Решать будешь ? Если будешь — опубликую после 1 сентября, задачи на сервере, который сейчас выключен. E>Ну я люблю решать интересные задачи. Как и все посетители этого раздела форума, я надеюсь.
Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни.
PD>>Не юли. Ты уже на структуры перекинулся и начал мне заявлять, что, мол, они могут не непрерывно лежать. А когда я тебя на этом поймал, заявил, что структуры в твоем понимании — и не struct вовсе, а некие произвольные структуры данных. Перечитай свои постинги. E>Да не волнуйся. Я знаю и как структуры лежат и как аллокатры работают и много чего ещё. Я правда имел в виду структуру данных. Если ты знаешь какое-то другое слово, которое позволяло бы избежать такой путаницы, то сообщи его.
Да не волнуюсь я. Ты заявляешь, что структура может лежать не непрерывно, так ? Я понимаю слово структура как struct и объясняю тебе, что этого быть не может — ни при flat модели. ни при сегментной. Тут вдруг выясняется, что структура — это не struct, а произвольная структура данных. Кто и когда заявлял, что произвольная структура данных должна лежать непрерывно ? Более того — ее вообще не сделаешь непрерывной, если специально не постараться (например, сериализация, или тот же VirtualAlloc). Утверждение твое, если иметь в виду struct — неверно, если иметь в виду произвольную структуру данных — бессмысленно, так как доказывает очевидное и не имеет отношения ни к одному из вопросов, поднятых раньше. Так что не юли. Просто ты , мягко выражаяь, перепутал логические адреса с физическим, отсюда и твой разговор о сегментной модели. В физической памяти struct может действительно лежать не непрерывно, но в логическом АП она всегда непрерывна. Вот и все. А признаться в том, что ты это перепутиал, у тебя смелости не хватило. вот ты и начал про произвольные структуры данных гоаорить.
>В любом случае это всё не важно, в контексте обсуждения списков, так я назвал структуры данных или нет. Я-то не преподаватель и грамотно выражаться не обязан
Ну а я не обязан медитировать насчет твоих неграмотных выражений
PD>>Что поделать, порой мне попадаются студенты, амбиции которых явно превышают их амуницию E>Какую такую амуницию? У меня тут жарко и я за компом в одних трусах
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Далеко не такой дорогой, как ты думаешь. Проверял.
Ну и во сколько раз дороже аллокировать 4К на VirtualAlloc, чем на стеке? На стеке это стоит одну несинхронизированную запись в память
E>>Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится. PD>Нет.
Как проверял?
PD>lpAddress PD>The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
По факту было не так. Увы.
E>>Обсуждалось как наждо делать односвязанные списки. PD>Не делать, а уничтожать с конца.
Ну ты расширил толкование задачи, и предложил закольцовывать список. Я показал, тебе, что закольцовывать никогда не надо. Но дискуссия вышла за рамки именно уничтожения списков, так как возникли вопросы нужно ли хранить указатель на последний элемент, нужны ли барьеры и т. д... В зависимости от структуры (это не struct, а просто русское слово) списка и стратегии удаления элементов, разные подходы оказываются в разной степени применимы. Так что вопросы о том, как список устроен и как уничтожать его элементы, оказались тесно связаны.
>>Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов. PD>Опять же не делать, а только уничтожать.
Ну да, при некотором подходе к организации односвязанного списка, при уничтожении его элемента нужен бинарный обмен данных между двумя элементами...
PD>Резюме простое — для решения разных задач нужны разные методы, и с этим никто не спорит. Твоя идея насчет буфера в экземпляре прокатит со страшной силой, если тебе придется в большинстве случае все же в итоге аллокировать буфер на стороне. Ничего кроме понапрасну потраченной памяти не будет, плюс копирование. В других случаях это может оказаться уместным.
Ну так, если ты правильно подберёшь константу, и тебе хватит стека, то хорошо работает всегда. Просто надо инструменты по назначению использовать.
Только это не моя идея. Я на её авторство нисколько не претендую. Я считаю, что это общее место, на самом деле
PD>Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни.
Ну я себе в аутглюке напоминалку завёл... Если хочешь -- можешь сделать так же
PD>Да не волнуюсь я. Ты заявляешь, что структура может лежать не непрерывно, так ?
Это всего лишь спор о словах. Просто ты меня неверно понял, а я не знаю, как в таком случае высказываться однозначно. Наверное надо писать полностью "структура данных", но длинно. IMHO, если собеседник пытается найти осмысленную трактовку тезисов, то есть работает в режиме конструктивного обсуждения, то такая омонимия не страшна. А если собеседник работает в режиме поиска неверных трактовок, то нафиг такие беседы
PD>Я понимаю слово структура как struct и объясняю тебе, что этого быть не может — ни при flat модели. ни при сегментной. Тут вдруг выясняется, что структура — это не struct, а произвольная структура данных. Кто и когда заявлял, что произвольная структура данных должна лежать непрерывно ? Более того — ее вообще не сделаешь непрерывной, если специально не постараться (например, сериализация, или тот же VirtualAlloc). Утверждение твое, если иметь в виду struct — неверно, если иметь в виду произвольную структуру данных — бессмысленно, так как доказывает очевидное и не имеет отношения ни к одному из вопросов, поднятых раньше.
Да не бессмысленно. Вот картинка сделанная поверх CAutoBuffer'а -- пример структуры данных, которая может лежать непрерывно, а может и в нескольких кусках памяти, и может иметь указатели внутрь себя, а может и не иметь...
И вот именно такие картинки в список, требующий бинарного обмена данных, не положишь, однако...
PD>Так что не юли. Просто ты , мягко выражаяь, перепутал логические адреса с физическим, отсюда и твой разговор о сегментной модели. В физической памяти struct может действительно лежать не непрерывно, но в логическом АП она всегда непрерывна.
Нет, не путал. Я про физические адреса вообще не думал, так как они из С++ недоступны.
Я тебе про другое говорил совсем. Если мы заменим указатель смещением, то мы не сможем сослаться на буфер аллокированный отдельно.
PD>Вот и все. А признаться в том, что ты это перепутиал, у тебя смелости не хватило. вот ты и начал про произвольные структуры данных гоаорить.
Телепалка у тебя не того, не прогрелась ещё наверное
PD>Ну а я не обязан медитировать насчет твоих неграмотных выражений
Ну так забудь уже о структурах тогда хоть прерывных, хоть нет
PD>М-да. Амуниция бывает не только в виде трусов
Доктор! Вы о чём собственно?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
PD>>Далеко не такой дорогой, как ты думаешь. Проверял. E>Ну и во сколько раз дороже аллокировать 4К на VirtualAlloc, чем на стеке? На стеке это стоит одну несинхронизированную запись в память
А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать.
E>>>Нет, это от системы зависит, на самом деле. На той ветке виндов, что росла из Чикаго, коммит происходил с гранулярностью в 10 страниц, помнится. PD>>Нет. E>Как проверял?
Элементарно. Резервируй 64 К и коммитируй 4К, потом попробуй обратиться к base + 4K и получишь AV.
PD>>lpAddress PD>>The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity. If the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
E>По факту было не так. Увы.
Обсуждать MSDN я не намерен.
E>>>Обсуждалось как наждо делать односвязанные списки. PD>>Не делать, а уничтожать с конца. E>Ну ты расширил толкование задачи, и предложил закольцовывать список.
Еще раз — прочти мое первое сообщение. Я только предложил (в шутку, кстати) алгоритм уничтожения с последнего элемента. Больше ничего. И позже я ничего о том, как эти списки создавать , не писал.
>Я показал, тебе, что закольцовывать никогда не надо. Но дискуссия вышла за рамки именно уничтожения списков, так как возникли вопросы нужно ли хранить указатель на последний элемент, нужны ли барьеры и т. д... В зависимости от структуры (это не struct, а просто русское слово) списка и стратегии удаления элементов, разные подходы оказываются в разной степени применимы. Так что вопросы о том, как список устроен и как уничтожать его элементы, оказались тесно связаны.
Ну и ладно. Примем применимость разных подходов (за что я всегда ратовал и, кстати, вовсе не объявлял тот прием, о котором писал, панацеей).
>>>Ты высказал идею, что можно их делать так, что при удалении элемента надо бинарно обменивать содержимое двух элементов. PD>>Опять же не делать, а только уничтожать. E>Ну да, при некотором подходе к организации односвязанного списка, при уничтожении его элемента нужен бинарный обмен данных между двумя элементами...
И все же насчет делать — с моей стороны ни слова не было.
PD>>Резюме простое — для решения разных задач нужны разные методы, и с этим никто не спорит. Твоя идея насчет буфера в экземпляре прокатит со страшной силой, если тебе придется в большинстве случае все же в итоге аллокировать буфер на стороне. Ничего кроме понапрасну потраченной памяти не будет, плюс копирование. В других случаях это может оказаться уместным.
E>Ну так, если ты правильно подберёшь константу, и тебе хватит стека, то хорошо работает всегда. Просто надо инструменты по назначению использовать.
Безусловно. Остается только хорошо подобрать константу
E>Только это не моя идея. Я на её авторство нисколько не претендую. Я считаю, что это общее место, на самом деле
Я тоже. Не хватало мне еще метод, описанный Виртом, себе приписывать
PD>>Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни. E>Ну я себе в аутглюке напоминалку завёл... Если хочешь -- можешь сделать так же
Не пользуюсь никакими средствами. кроме головы.
PD>>Да не волнуюсь я. Ты заявляешь, что структура может лежать не непрерывно, так ? E>Это всего лишь спор о словах. Просто ты меня неверно понял, а я не знаю, как в таком случае высказываться однозначно. Наверное надо писать полностью "структура данных", но длинно. IMHO, если собеседник пытается найти осмысленную трактовку тезисов, то есть работает в режиме конструктивного обсуждения, то такая омонимия не страшна. А если собеседник работает в режиме поиска неверных трактовок, то нафиг такие беседы
PD>>Я понимаю слово структура как struct и объясняю тебе, что этого быть не может — ни при flat модели. ни при сегментной. Тут вдруг выясняется, что структура — это не struct, а произвольная структура данных. Кто и когда заявлял, что произвольная структура данных должна лежать непрерывно ? Более того — ее вообще не сделаешь непрерывной, если специально не постараться (например, сериализация, или тот же VirtualAlloc). Утверждение твое, если иметь в виду struct — неверно, если иметь в виду произвольную структуру данных — бессмысленно, так как доказывает очевидное и не имеет отношения ни к одному из вопросов, поднятых раньше. E>Да не бессмысленно. Вот картинка сделанная поверх CAutoBuffer'а -- пример структуры данных, которая может лежать непрерывно, а может и в нескольких кусках памяти, и может иметь указатели внутрь себя, а может и не иметь...
Продолжаешь выкручиваться.
E>И вот именно такие картинки в список, требующий бинарного обмена данных, не положишь, однако...
Элементарно положишь. Я как-то говорил — лучшеее решение — иметь в list_node указатель на данные. Указатели элементарно свопируются, а данные трогать незачем.
PD>>Так что не юли. Просто ты , мягко выражаяь, перепутал логические адреса с физическим, отсюда и твой разговор о сегментной модели. В физической памяти struct может действительно лежать не непрерывно, но в логическом АП она всегда непрерывна. E>Нет, не путал. Я про физические адреса вообще не думал, так как они из С++ недоступны.
М-да... Слушай, Егор, ты меня чем дальше, тем больше удивляешь, честное слово. При чем тут C++ ? Они недоступны для программ 3-го кольца, независимо от того, на чем они написаны. Они доступны всем средствам 0-го кольца (драйверам, самой ОС) независимо от того, на чем они написаны. Или ты хочешь сказать, что на асме в 3 кольце физические адреса будут доступны ? Огорчу тебя — это не так.
Драйверы на С++ хоть и редко, но пишут, и там они вполне доступны. В огороде бузина, а в Киеве дядька.
E>Я тебе про другое говорил совсем. Если мы заменим указатель смещением, то мы не сможем сослаться на буфер аллокированный отдельно.
Не сможем. Я о пределах применимости метода Вирта писал с самого начала.
PD>>Вот и все. А признаться в том, что ты это перепутиал, у тебя смелости не хватило. вот ты и начал про произвольные структуры данных гоаорить. E>Телепалка у тебя не того, не прогрелась ещё наверное
Вполне прогрелась. Интересно, как ты теперь выкручиваться будешь, насчет С++ и физических адресов.
PD>>Ну а я не обязан медитировать насчет твоих неграмотных выражений E>Ну так забудь уже о структурах тогда хоть прерывных, хоть нет
Вообще-то лучше бы забыть о специалистах, которые путают режим ядра/супервизора с языком программирования. Да вот не дают они забыть. Ну а я по слабости своей никак эту дискуссию оборвать не решусь. Может, ты сам ее закончишь ? А то, боюсь, ты еще несколько открытий сделаешь
PD>>М-да. Амуниция бывает не только в виде трусов E>Доктор! Вы о чём собственно?
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать.
Это другая задача.
PD>Элементарно. Резервируй 64 К и коммитируй 4К, потом попробуй обратиться к base + 4K и получишь AV.
На Win95 не получал. Там реально коммитили по 40К. Такое вот было экспериментальное наблюдение...
E>>По факту было не так. Увы. PD>Обсуждать MSDN я не намерен.
То, что коммитили больше, чем просишь, никак не противоречит MSDN.
PD>И все же насчет делать — с моей стороны ни слова не было.
Было. Например, ты писал, что всегда в своих списках ты всегда хранишь указатель на хвост...
PD>Безусловно. Остается только хорошо подобрать константу
Это не сложно. Прогони на типичных задачах программу и узнаешь необходимые размеры буфера...
PD>>>Ладно, если не забуду, выложу после 1.9. Если забуду (начало семестра!) — напомни. E>>Ну я себе в аутглюке напоминалку завёл... Если хочешь -- можешь сделать так же PD>Не пользуюсь никакими средствами. кроме головы.
Ну тебе виднее, как оно надёжнее выходит
PD>Продолжаешь выкручиваться.
Или чинить телепалку.
PD>Элементарно положишь. Я как-то говорил — лучшеее решение — иметь в list_node указатель на данные. Указатели элементарно свопируются, а данные трогать незачем.
Это ПЛОХОЕ решение!!! Если у тебя есть место под лишний указатель на ноду, то лучше сделать список двусвязанным, и ничего никогда не обменивать
Кроме того, что твой подход с указателем на данные гарантирует лишнюю косвенность при любом доступе (то есть тормоза забесплатно), то это ещё и увеличивает количество дорогих довольно аллокаций!
PD>М-да... Слушай, Егор, ты меня чем дальше, тем больше удивляешь, честное слово. При чем тут C++ ? Они недоступны для программ 3-го кольца, независимо от того, на чем они написаны. Они доступны всем средствам 0-го кольца (драйверам, самой ОС) независимо от того, на чем они написаны. Или ты хочешь сказать, что на асме в 3 кольце физические адреса будут доступны ? Огорчу тебя — это не так.
Блин! Мы с тобой обсуждаем списки или что?
PD>Драйверы на С++ хоть и редко, но пишут, и там они вполне доступны. В огороде бузина, а в Киеве дядька.
Но и там всё равно работа с памятью идёт через логические адреса, а не через физические. Или ты знаешь реализацию С++ под ядро винды, которая умеет работать с указателями на физ. адрес?
PD>Вполне прогрелась. Интересно, как ты теперь выкручиваться будешь, насчет С++ и физических адресов.
Ну ты реализацию С++, которая с физическим адресами работает приведи, а там поговорим. Вполне так может быть, что я про такую просто не знаю. Ну значит узнаю
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать. E>Это другая задача.
См. выделенное.
PD>>Элементарно. Резервируй 64 К и коммитируй 4К, потом попробуй обратиться к base + 4K и получишь AV. E>На Win95 не получал. Там реально коммитили по 40К. Такое вот было экспериментальное наблюдение...
Закончим это обсуждение, все равно проверить негде. Но насчет 40 К — очень странно. Резервируем 64, коммитриуем 40, а потом как оставшиеся 24 коммитировать ? Дырки мне не нужны.
E>>>По факту было не так. Увы. PD>>Обсуждать MSDN я не намерен. E>То, что коммитили больше, чем просишь, никак не противоречит MSDN.
Учи матчасть.
lpAddress
the memory is already reserved and is being committed, the address is rounded down to the next page boundary.
dwSize
The size of the region, in bytes. If the lpAddress parameter is NULL, this value is rounded up to the next page boundary. Otherwise, the allocated pages include all pages containing one or more bytes in the range from lpAddress to lpAddress+dwSize. This means that a 2-byte range straddling a page boundary causes both pages to be included in the allocated region.
flAllocationType
PD>>И все же насчет делать — с моей стороны ни слова не было. E>Было. Например, ты писал, что всегда в своих списках ты всегда хранишь указатель на хвост...
PD>>Безусловно. Остается только хорошо подобрать константу E>Это не сложно. Прогони на типичных задачах программу и узнаешь необходимые размеры буфера...
М-да. Остается мне только найти типичные задачи
PD>>Элементарно положишь. Я как-то говорил — лучшеее решение — иметь в list_node указатель на данные. Указатели элементарно свопируются, а данные трогать незачем. E>Это ПЛОХОЕ решение!!! Если у тебя есть место под лишний указатель на ноду, то лучше сделать список двусвязанным, и ничего никогда не обменивать E>Кроме того, что твой подход с указателем на данные гарантирует лишнюю косвенность при любом доступе (то есть тормоза забесплатно), то это ещё и увеличивает количество дорогих довольно аллокаций!
PD>>М-да... Слушай, Егор, ты меня чем дальше, тем больше удивляешь, честное слово. При чем тут C++ ? Они недоступны для программ 3-го кольца, независимо от того, на чем они написаны. Они доступны всем средствам 0-го кольца (драйверам, самой ОС) независимо от того, на чем они написаны. Или ты хочешь сказать, что на асме в 3 кольце физические адреса будут доступны ? Огорчу тебя — это не так. E>Блин! Мы с тобой обсуждаем списки или что?
Я в данный момент обсвждаю твое заявление насчет невозможности доступа к физической памяти из С++. Я тебя за язык не тянул, сам напросился.
PD>>Драйверы на С++ хоть и редко, но пишут, и там они вполне доступны. В огороде бузина, а в Киеве дядька. E>Но и там всё равно работа с памятью идёт через логические адреса, а не через физические.
О господи! Ты же просто элементарных вещей не понимаешь!
>Или ты знаешь реализацию С++ под ядро винды, которая умеет работать с указателями на физ. адрес?
Уф. Придется ликбез устроить.
С++ не выделяет память. Ни в 0-м, ни в 3-м кольце. Не умеет он этого делать. Память выделяет некий системный вызов (вызов API), который ее запрашивает у системы. Максимум, что может делать RTL C++ — это запросить большой блок и устроить на нем свое подраспределение. Так работала куча в стародавние времена. Сейчас это передано системе (HeapAlloc, к вызову которой в конечном счете приводит new/malloc и т.д.).
Если системный вызов выделяет виртуальную память, то получим виртуальный адрес (можно и в 0, и в 3 кольце)
Если системный вызов выделяет физическую память, то получим физический адрес (можно только в 0 кольце)
Если когда-нибудь появится химическая память, то будет вызов для ее получения и получим химический адрес
PD>>Вполне прогрелась. Интересно, как ты теперь выкручиваться будешь, насчет С++ и физических адресов. E>Ну ты реализацию С++, которая с физическим адресами работает приведи, а там поговорим. Вполне так может быть, что я про такую просто не знаю. Ну значит узнаю
В огороде бузина. а в Киеве дядька. Ты этой фразой просто признался в том, что ты совершенно ничего не понимаешь в том, как устроено ядро.
Ладно, Егор. все, хватит. За тобой последнее слово, но вопросов не задавай — я не отвечу.
Мой тебе совет — проштудируй первую книгу Рихтера и книгу Соломона-Русстновича о внутреннем устройстве Windows. Пока что ты тут понимаешь не больше, чем я в программировании для iPad
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>>>А ты сравни лучше с new/malloc и memcpy, которые тебе, возможно, придется делать. E>>Это другая задача. PD>См. выделенное.
Во-первых, CAutoBuffer, так же, как и alloca предназначен для таких сценариев, когда буфер не увеличивают, или увеличивают очень редко.
Во-вторых, тут получается хитрый размен.
Для маленьких буферов, которые бывают часто, имеем бесплатную аллокацию. Зато для больших имеем new.
При этом, большой буффер, кроме того, что выделять, надо потом ещё и обработать, по крайней мере инициализировать. По сравнению с инициализацией большого буфера new уже не выглядит таким дорогим. То есть, если мы будем измерять производительность системы в том, сколько байт в секунду она может обработать, то получим выигрыш. Кроме того, new не обязан быть дороже VirtualAlloc. Я знаю аллокаторы, которые быстрее.
Ну и, кроме всего прочего, VA не так экономно расходует адресное пространство.
PD>М-да. Остается мне только найти типичные задачи
Ну, обычно, когда ПО разрабатывают в утилитарных целях, типичные задачи знают. Это просто необходимо для оптимизации и настройки, так как часто оптимизация, после ловле багов, превращается в правильный выбор в тех или иных разменах, вроде память vs скорость. Ну, во всяком случае по моему опыту обычно бывает так.
PD>Я в данный момент обсуждаю твое заявление насчет невозможности доступа к физической памяти из С++. Я тебя за язык не тянул, сам напросился.
Ну какой смысл искать оговорки и неточности? Если ты пишешь обычную программу на С++ с рантаймом, стандартными потоками и прочей поддержкой стандарта, то ты никак не имеешь доступа к физ. адресам...
E>>Но и там всё равно работа с памятью идёт через логические адреса, а не через физические. PD>О господи! Ты же просто элементарных вещей не понимаешь! PD>На, посмотри PD>http://msdn.microsoft.com/en-us/library/ff554460(VS.85).aspx
MmAllocateContiguousMemory returns the base virtual address for the allocated memory. If the request cannot be satisfied, NULL is returned.
Обрати внимание, что работа со стороны программы всё равно идёт через virtual address
PD>С++ не выделяет память. Ни в 0-м, ни в 3-м кольце. Не умеет он этого делать. Память выделяет некий системный вызов (вызов API), который ее запрашивает у системы. Максимум, что может делать RTL C++ — это запросить большой блок и устроить на нем свое подраспределение. Так работала куча в стародавние времена. Сейчас это передано системе (HeapAlloc, к вызову которой в конечном счете приводит new/malloc и т.д.).
Ошибаешься. С точки зрения С++ программы, как раз С++ тебе память и выделяет. И как раз в этой вот выделенной рантаймом С++ памяти работает, например, std::string А то, как именно рантайм это всё делает -- это подробности данной реализации С++
PD>Если системный вызов выделяет виртуальную память, то получим виртуальный адрес (можно и в 0, и в 3 кольце) PD>Если системный вызов выделяет физическую память, то получим физический адрес (можно только в 0 кольце)
Это всего лишь функции. Функции могут быть любыми. Мы же говорили про списки там, и менеджеры кусков памяти, который работают с С++ указателями? Так указатели в винде всё равно будут работать через страничное преобразование, то есть, прямого доступа из самого языка к физическим адресам нет...
Или ты хочешь сказать, что под винду бывают драйвера, которые работают при отключенном страничном преобразовании? Я про такое не знаю, но я в этом не спец. Возможно и бывают, но обычные драйвера, что под NT, что под чикагу работают в логических адресах...
PD>В огороде бузина. а в Киеве дядька. Ты этой фразой просто признался в том, что ты совершенно ничего не понимаешь в том, как устроено ядро.
Во-первых, я на знание того, как устроено ядро не претендую. IMHO, досконально это могут знать только разработчики винды.
Во-вторых, к тому, как писать списки, это, IMHO, не имеет никакого о отношения.
Ну и в-третьих, если говорить в терминах С++, то доступ к памяти осуществляется через её модель. С++ предоставляет некую машину для работы с данными, которая реализует указатели и операции над ними. Вот если бы была реализация, где можно описать такой тип указателя, что операции по нему происходили бы по физическим адресам, минуя страничное преобразование и сегменты, то можно бы было говорить, что из С++ можно получить доступ к физическим адресам. А так, извини, но нет. Или ты в списке планируешь доступ к памяти через API осуществлять?
PD>Мой тебе совет — проштудируй первую книгу Рихтера и книгу Соломона-Русстновича о внутреннем устройстве Windows. Пока что ты тут понимаешь не больше, чем я в программировании для iPad
За совет спасибо. Первую я читал, а вторую не помню. Как она называется и зачем нужно её изучать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
MmAllocateContiguousMemory returns the base virtual address for the allocated memory. If the request cannot be satisfied, NULL is returned.
E>Обрати внимание, что работа со стороны программы всё равно идёт через virtual address
Нет, просто эта функция еще и маппирует в вирт. АП. Вот еще пример
MmGetPhysicalAddress
The MmGetPhysicalAddress routine returns the physical address corresponding to a valid nonpaged virtual address.
PHYSICAL_ADDRESS MmGetPhysicalAddress(
__in PVOID BaseAddress
);
Parameters
BaseAddress [in]
Pointer to the virtual address for which to return the physical address.
E>За совет спасибо. Первую я читал, а вторую не помню. Как она называется и зачем нужно её изучать?
Соломон, Руссинович. Внутреннее устройство Windows ... (было 2 издания, в одном вместо многоточия 2000, в другом 2003/XP). Изучать ее не нужно, а прочитать внимательно надо, чтобы понимать, кто за что отвечает и как там внутри все устроено.
Здравствуйте, Erop, Вы писали:
E>Ну и в-третьих, если говорить в терминах С++, то доступ к памяти осуществляется через её модель. С++ предоставляет некую машину для работы с данными, которая реализует указатели и операции над ними. Вот если бы была реализация, где можно описать такой тип указателя, что операции по нему происходили бы по физическим адресам, минуя страничное преобразование и сегменты, то можно бы было говорить, что из С++ можно получить доступ к физическим адресам. А так, извини, но нет. Или ты в списке планируешь доступ к памяти через API осуществлять?
Сделай милость, не говори о том. чего не знаешь. Эта тема весьма серьезна, и здесь многое чего есть. Посмотри хотя бы VirtualAlloc с флагом MEM_PHYSICAL, а потом AllocateUserPhysicalPages, MapUserPhysicalPages.
Это и выделение памяти, причем физической , и механизм доступа к ней (именно через АПИ), и даже доступ за пределами 4G в 32-битной системе, что уж с твоей точки зрения вообще невозможно. Возможно. Управление памятью — вопрос сложный, а ты в нем просто не разбираешься, ну и не надо высказываться.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>PHYSICAL_ADDRESS MmGetPhysicalAddress( PD> __in PVOID BaseAddress PD>); PD>Parameters PD>BaseAddress [in] PD>Pointer to the virtual address for which to return the physical address.
Ну и что? Как потом по PHYSICAL_ADDRESS получить или записать данные? С++ этого вроде не умеет.
PD>Соломон, Руссинович. Внутреннее устройство Windows ... (было 2 издания, в одном вместо многоточия 2000, в другом 2003/XP). Изучать ее не нужно, а прочитать внимательно надо, чтобы понимать, кто за что отвечает и как там внутри все устроено.
Спасибо. Марк Руссинович мужчина, похоже, интересный.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Сделай милость, не говори о том. чего не знаешь. Эта тема весьма серьезна, и здесь многое чего есть. Посмотри хотя бы VirtualAlloc с флагом MEM_PHYSICAL, а потом AllocateUserPhysicalPages, MapUserPhysicalPages.
PD>Это и выделение памяти, причем физической , и механизм доступа к ней (именно через АПИ), и даже доступ за пределами 4G в 32-битной системе, что уж с твоей точки зрения вообще невозможно. Возможно. Управление памятью — вопрос сложный, а ты в нем просто не разбираешься, ну и не надо высказываться.
Через API можно много куда доступ получить. Но при чём тут указатели и вообще модель памяти С++? С++ этого всего не умеет. Поэтому обсуждать все эти хитрости, при разработке списка на указателях смысла нет никакого
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Через API можно много куда доступ получить. Но при чём тут указатели и вообще модель памяти С++?
При том, что нет модели памяти С++. Есть модель памяти операционной системы, в которой работает программа, написанная хоть на С++, хоть на Дельфи, хоть на асме.
>С++ этого всего не умеет.
С++ вообще ничего не умеет. А программисты,пишущие на нем, могут сделать все, что позволяет сделать операционная система, в которой эта программа или модуль работает.
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>Егор,хватит. Пойми, наконец, что С++ тут вообще ни при чем. Если я на асме напишу этот вызов — что изменится ?
Да ничего не изменится. В том режиме проца, в котором работает винда адреса всё равно будут линейными, а не физическими. С++ тут при том, чот в принципе, можно представить себе реализацию, которая поддерживает особый тип указателей на физические адреса. И при их разыменовании генерит вызовы соответсвующего API. Но такой реализации С++, насколько я знаю, нет. Так что как ни крутись, но при работе по С++ным указателям ты будешь иметь дело с логическими адресами, и физические тут не при чём.
В общем, либо приыведи пример, когда собственно сам С++ код, а не вызовы стороннего по отношению к языку АPI, позволяет работать непосредственно с физ. адресами, либо признавай, что из С++ физ. адреса недоступны. API, которое позволяет работать с физ. адресами может быть доступно, а вот сама по себе работа, непочредственно через указатели -- нет
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Pavel Dvorkin, Вы писали:
PD>При том, что нет модели памяти С++.
Это не так. Необходимые свойства модели памяти С++ ЯВНО описаны в стандерте языка. Почитай, тоже полезно
PD>Есть модель памяти операционной системы, в которой работает программа, написанная хоть на С++, хоть на Дельфи, хоть на асме. Это другой уровень абстракции. Модель памяти С++ реализуется поверх модели памяти ОС. При этом они не обязаны совпадать.
PD>С++ вообще ничего не умеет.
Неправда. С++ код умеет непосредственно работать с памятью, по логическим адресам. Умеет вызывать процедуры, тоде по логическим адресам.
PD>А программисты,пишущие на нем, могут сделать все, что позволяет сделать операционная система, в которой эта программа или модуль работает.
Это другой уровень абстракции, не имеющий непосредственного отношения к С++. С++ реализует свою модель памяти поверх модели памяти ОС. Например, можно реализовать С++, который будет на 32-й ОС работать с более длинными адресами. Просто это будет несколько неэффективно. Вот.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском