Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2006.03.05;
Скачать: [xml.tar.bz2];

Вниз

Проблема с GetMem   Найти похожие ветки 

 
YuRock ©   (2006-02-15 01:28) [0]

Добрый. Сомневался, в какую конференцию написать - решил сюда.
Итак, написал я прогу - загрузчик файлов (по HTTP, используя Indy - но это не важно). Функциональность закачки/докачки решил запихнуть
в dll, чтоб потом в других прогах использовать (ну очень мне понравилось, как я написал :) - работает на ура).

Хочу сразу сказать, что вызывается из dll одна функция:
function HTTPLoadFile( nFileHandle: Integer; sURL: LPSTR; sFileName: LPSTR; var nFileSize: Int64; var nFileReaded: Int64; bResume: BOOL ): BOOL;
При чем память под sURL и sFileName выделяется и удаляется в основном приложении. Более того - через GlobalAlloc(GMEM_FIXED).

Итак, приложение стало иногда (раз в час, примерно) страшно валиться (то просто прога "выйдет из себя" молча, то AV в этой dll). Я для тестов поднял апач на локальной машине и начал одновременно закачивать 100 файлов - стало валиться за 5-10 секунд.

Т.к. отладчик call-stack не показывал, я засунул в отдельный try..except каждую строчку кода этой функцции, в except"е поставил Exit и на нем - break-point.
И что интересно - исключение появлялось в рандомном порядке в разных местах, НО ЧАЩЕ ВСЕГО - при вызове GetMem - для выделения буффера (размер в зависимости от высчитанной текущей скорости закачки).

Я, ради прикола, заменил GetMem/FreeMem на GlobalAlloc/GlobalFree и падать стало в 20 раз реже - уже около минуты прога работала.
В том, что ошибка останется - я и не сомневался, т.к. я использовал Indy - а это классы, для выделения памяти под структуры объектов которых используется тот же GetMem.

Пробовал на D6, и D7, Win2k и XP - одно и то же.
После этого я попробовал подключить ShareMem - и все заработало идеально (даже с GetMem/FreeMem) (как раньше, до переноса ф-ции в отдельную dll).

Но т.к. ShareMem - это не выход (эту dll уже ждали несколько проектов на вижуале, да и вообще...), я исхитрился следующим образом:
убрал ShareMem, а вместо этого переопределил AllocMem/FreeMem/ReAllocMem на GlobalAlloc/GlobalFree/GlobalReAlloc через SetMemoryManager (только в dll).

И теперь все работает великолепно. Вот, появилось время написать сюда и задать вопрос - а что, в dll нельзя использовать стандартный GetMem? Почему? Ведь, вроде-бы, хоть image base и отдельный, но указатели в каждом модуле используются строго только в них...

Очень хотелось бы услышать мнение мастеров.
Спасибо.


 
YuRock ©   (2006-02-15 05:30) [1]

Пока писал этот вопрос - возникла одна идея, которая оказалась в итоге правильной - и я сам разобрался, в чем проблема :)

В принципе, это будет полезно для многих, поэтому расскажу.

Так вот, дело в том, что моя ф-ция из dll вызывалась из многих потоков, созданных BeginThread, но в основном приложении. Поэтому переменная IsMultiThread принимала значение True только в основной программе, а в dll оставалась равной False.

Просмотрев реализацию работы делфовой кучи (в частности - ф-цию SysGetMem), стало очевидно, что без синхронизации (которая начинает работать только если IsMultiThread = True) будут происходить страшные вещи :) Именно они и происходили.

Так что теперь при написании dll первое, что я обязательно буду делать - это писать IsMultiThread := True в инициализации. Мало ли, как будут вызываться ф-ции из нее... И всем рекомендую.


 
pargo ©   (2006-02-15 05:41) [2]

Интересно. Попробую. Я, тоже, ломал над этим голову.:((


 
Leonid Troyanovsky ©   (2006-02-15 09:10) [3]


> YuRock ©   (15.02.06 01:28)  

> в dll, чтоб потом в других прогах использовать (ну очень


Не очень понятно зачем, собс-но, dll.
Т.е., если другие нуждаются в закачке/докачке пусть пользуют саму
программу, которую можно сделать, например, консолью (для
работы в конвеере) или сервисом.

Это я к тому, что первое решение повлекло последующие,
не менее спорные.

--
Regards, LVT.


 
YuRock ©   (2006-02-15 09:25) [4]


> Leonid Troyanovsky ©   (15.02.06 09:10) [3]
>
> Не очень понятно зачем, собс-но, dll.
> Т.е., если другие нуждаются в закачке/докачке пусть пользуют
> саму
> программу, которую можно сделать, например, консолью (для
> работы в конвеере) или сервисом.


Немножко неясно, что именно "Не очень понятно" :)

Мне постоянно приходится работать с разными средствами: Delphi, VC, C#... вплоть до яваскрипта.
И почти всегда нужна ф-ция закачки файла. Проще всего (и быстрее, и удобнее, и возможностей больше) - запихнуть ее в dll и потом использовать, где угодно.


> Это я к тому, что первое решение повлекло последующие,
> не менее спорные.


Кгм...
1) Последующие спорные решения - это какие?
2) Сделать консоль или сервис - было бы менее спорным решением? :)


 
Leonid Troyanovsky ©   (2006-02-15 09:32) [5]


> YuRock ©   (15.02.06 05:30) [1]

> буду делать - это писать IsMultiThread := True в инициализации.
>  Мало ли, как будут вызываться ф-ции из нее... И


Предположим, что для собственных нужд dll нужен некий буфер,
(что уже, само по себе, вызывает много вопросов).
Ну и выделит она себе VirtualAlloc, сколько надо.
А использование операций, требующих неявного перераспределения
памяти (скажем, работа со строками) также необосновано в
условиях, что библиотека может применяться кем попало.

Т.е., одной только установки IsMultiThread - мало.
Или, лучше сказать так, надо писать билиотеку так, чтобы
оная установка не требовалась.

--
Regards, LVT.


 
Leonid Troyanovsky ©   (2006-02-15 09:44) [6]


> YuRock ©   (15.02.06 09:25) [4]


> Мне постоянно приходится работать с разными средствами:
> Delphi, VC, C#... вплоть до яваскрипта.
> И почти всегда нужна ф-ция закачки файла. Проще всего (и
> быстрее, и удобнее, и возможностей больше) - запихнуть ее
> в dll и потом использовать, где угодно.

 Не dll.
 В том смысле, что это должен быть ActiveX, OLE server & other COM.

> 2) Сделать консоль или сервис - было бы менее спорным решением?
>  :)

Конечно. Чего может делать эта весчь?
Тащить файлы и сохранять их на диск.
Ну и, возможно, уведомлять клиента об окончании загрузки.

--
Regards, LVT.


 
YuRock ©   (2006-02-15 09:46) [7]


> Leonid Troyanovsky ©   (15.02.06 09:32) [5]
>
> Предположим, что для собственных нужд dll нужен некий буфер,
>
> (что уже, само по себе, вызывает много вопросов).
> Ну и выделит она себе VirtualAlloc, сколько надо.
> А использование операций, требующих неявного перераспределения
> памяти (скажем, работа со строками) также необосновано в
> условиях, что библиотека может применяться кем попало.


Это к чему? Не могу понять, извините...


> Т.е., одной только установки IsMultiThread - мало.


Хорошо, чего-то еще не хватает для полной уверенности? Я что-то упустил?


> Или, лучше сказать так, надо писать билиотеку так, чтобы
> оная установка не требовалась.


Есть другие варианты? Как написать гарантированно рабочую библиотеку, использующую стандартный делфовый менеджер памяти, не устанавливая IsMultiThread=True?


 
YuRock ©   (2006-02-15 09:57) [8]


> Leonid Troyanovsky ©   (15.02.06 09:44) [6]
>
>  Не dll.
>  В том смысле, что это должен быть ActiveX, OLE server &
> other COM.
>


Нет ничего быстрее и проще dll. А "ActiveX, OLE server & other COM" - добавят только тормозов и гемора с регистрацией и т.п.
Плюс использовать их гораздо более неудобно, чем dll. Больше писанины получится.

В общем, тут даже спорить не буду. Нет смысла.


>
> Конечно. Чего может делать эта весчь?
> Тащить файлы и сохранять их на диск.
> Ну и, возможно, уведомлять клиента об окончании загрузки.
>


Конечно. В данный момент - да. И еще все то, что я захочу и сделаю. И главное (повторяю еще раз) - простота и удобство использования.


 
Leonid Troyanovsky ©   (2006-02-15 10:10) [9]


> YuRock ©   (15.02.06 09:46) [7]

> Хорошо, чего-то еще не хватает для полной уверенности?


Для того, чтобы библиотека была гарантировано многопоточной
она не должна использовать то, что может сделать ее немногопоточной.
В частности, использование сторонних компонентов (как, собс-но,
_любых_ объектов). Т.е., всякое применение должно быть тщательно
изучено и обосновано. Что сделать в общем случае не просто, и гораздо
проще сделать работоспособное отдельно стоящее приложение.
Общение с таким приложением не представляет большого труда для
любых ЯВУ еще со времен ДОС.

Для иных случаев нужен COM, для чего и создавался.

--
Regards, LVT.


 
YuRock ©   (2006-02-15 10:16) [10]


> Для того, чтобы библиотека была гарантировано многопоточной
> она не должна использовать то, что может сделать ее немногопоточной.
>
> В частности, использование сторонних компонентов (как, собс-
> но,
> _любых_ объектов).


Эти сторонние компоненты так же могут сделать немногопоточным и основное приложение. И будут ту же грабли. В чем выйгрыш?


 
Leonid Troyanovsky ©   (2006-02-15 10:26) [11]


> YuRock ©   (15.02.06 10:16) [10]

> Эти сторонние компоненты так же могут сделать немногопоточным
> и основное приложение. И будут ту же грабли. В чем выйгрыш?


Если приложение однопоточное, то оно им и будет
(всякие CreateRemoteThread не берем в рассмотрение).

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

--
Regards, LVT.


 
YuRock ©   (2006-02-15 10:34) [12]


> Если приложение однопоточное, то оно им и будет
> (всякие CreateRemoteThread не берем в рассмотрение).
>
> Т.е., сколько раз его запустят (в любом из потоков, из любой
> библиотеки,
> из любого скрипта и т.д.) - оно будет работать так, как
> оно и работало,
> скажем, впервые после компиляции.


Не пойму, о чем вы говорите. Вначале вы, на сколько я понял, утверждали, что лучше вместо многопоточной библиотеки сделать консольное приложение. Естественно, что ф-ция, вызываемая из множества потоков (такая задача) будет вызываться из множества потоков что в dll, что в приложении.

При чем здесь теперь однопоточное приложение?


 
Leonid Troyanovsky ©   (2006-02-15 10:43) [13]


> YuRock ©   (15.02.06 10:34) [12]

> Естественно, что ф-ция, вызываемая
> из множества потоков (такая задача) будет вызываться из
> множества потоков что в dll, что в приложении.


Ну и пусть вызывается.
Если эта функция выполняется отдельным приложением, не вижу
особых затруднений.

--
Regards, LVT.


 
YuRock ©   (2006-02-15 10:46) [14]

Я тоже.


 
Defunct ©   (2006-02-16 01:46) [15]

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


Что-то не пойму я. А что есть какие-то ограничения на использование CS в dll?


 
Leonid Troyanovsky ©   (2006-02-16 08:25) [16]


> Defunct ©   (16.02.06 01:46) [15]

>  А что есть какие-то ограничения на использование CS в dll?


Есть и такие - нельзя использовать функции ожидания в dllproc.

Однако, мне тоже надоела эта тема.
Т.е., кто хочет делать dll из exe, пусть делают.
Надеюсь, что пользовать их мне не придется.

--
Regards, LVT.


 
evvcom ©   (2006-02-16 09:24) [17]


> function HTTPLoadFile( nFileHandle: Integer; sURL: LPSTR;
>  sFileName: LPSTR; var nFileSize: Int64; var nFileReaded:
>  Int64; bResume: BOOL ): BOOL;
> При чем память под sURL и sFileName выделяется и удаляется
> в основном приложении. Более того - через GlobalAlloc(GMEM_FIXED).

Не совсем ясно что, зачем и где.
Если dll используется из разных приложений, то об использовании дельфового менеджера для выделения памяти под данные, которые будут переданы в чужеродные приложения, надо забыть. Никаких ShareMem! Пусть внутри под строки, массивы память выделяет DelphiMM, но никакой передачи этих указателей наружу!
Далее. Память выделять можно 2-мя способами: 1) в exe и передавать указатель в dll, и 2) в dll, возвращая указатель в exe. Но освобождаться она должна там, где выделялась.
1 способ неудобен тем, что изначально в общем случае неизвестно требуемое количество байт, поэтому в данном случае лучше пойти по 2-му пути.
В твоей HTTPLoadFile не ясно использование nFileHandle. По моему разумению это должен быть var-параметр. sURL и sFileName должны быть const, опять же имхо. И тогда вроде становится многое логичным. Естественно должна быть тогда еще функция, которая по nFileHandle либо возвращает указатель на собственно сами данные, либо их копирует в память выделенную уже в host-приложении. И функция типа CloseHandle, которая и освобождает память (2-ой способ).



Страницы: 1 вся ветка

Форум: "Начинающим";
Текущий архив: 2006.03.05;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.52 MB
Время: 0.012 c
2-1140265408
BaBayka007
2006-02-18 15:23
2006.03.05
Цикл?.... а вот как - что-то совсем у меня ни как.....:)


15-1139668558
ArtemESC
2006-02-11 17:35
2006.03.05
Компилятор Pascal для HP iPAQ...


8-1127324360
NightLord
2005-09-21 21:39
2006.03.05
Web-камера


3-1136982771
tytus
2006-01-11 15:32
2006.03.05
ХЕЛППП!!! BDEError Record/Key Deleted


2-1139928550
VanDet
2006-02-14 17:49
2006.03.05
Помогите пожалуйста решить мне задачу





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский