![]() |
|
Модераторы: Snowy, bartram, MetalFan, bems, Poseidon, Riply |
![]()
|
|
| Coder |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 733 Регистрация: 13.12.2004 Репутация: 1 Всего: 11 |
Суть в следующем - пытаюсь предотвратить одновременный доступ нескольких потоков к процедуре добавления новых данных в общий лог.
Модуль ведения лога:
Из кода видно, что процедура AddLogMessage() в конкретный момент времени должна выполнятся одним потоком. Тестирую так:
Самое интересное, что если убрать EnterCriticalSection(lCritSect) и LeaveCriticalSection(lCritSect), то AV вываливается при первом же запуске теста. В противном случае AV вываливается не сразу - а скажем после 4, 5 вызовов тестового цикла (for testI:=1 to 10 do). В чем здесь может быть дело? |
||||
|
|||||
| Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Неряшливо написанный код (пусть даже временный) - основная причина всяких "багов" и ошибок. Приведи его в порядок: 1. Где try/finally ? 2. Где закрытие Handle`ов ? 3. Почему randomize вызывается столько раз ? Теперь насчет структуры: Вместо CreateThread, настоятельно рекомендую использовать BeginThread, либо тщательно изучить и понять их отличие. (Там все сложнее, чем просто установка IsMultiThread) А если все же (по религиозным соображениям то попробуй обернуть в кр. секцию не AddLogMessage, а _AddLog и посмотри как измениться поведение |
|||
|
||||
| Coder |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 733 Регистрация: 13.12.2004 Репутация: 1 Всего: 11 |
Я не вижу смысла расставлять их по данному коду. Здесь это тоже не критично важно. Согласен - нужно вынести его из кода потоковой функции.
Так не пойдет - все потоки будут ждать пока 1 не добавит все 5 сообщений. Тем более что _AddLog тестовая процедура, на практике все потоки пользуются AddLogMessage. |
|||
|
||||
| Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
||||
|
||||
| Coder |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 733 Регистрация: 13.12.2004 Репутация: 1 Всего: 11 |
Riply, ну хорошо, handler`ы закрою . Что изменится? Мне не понятно, почему программа падает, при "интенсивном" обращении к процедуре AddLogMessage. Всего-то
Riply, Все-таки это тестовый пример для тестирования главной процедуры, и не важно в каком состоянии будет поток после выполнения кода, главное чтобы он N число раз выполнил AddLogMessage. |
|||
|
||||
| CodeMonkey |
|
|||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
1. Если используется CreateThread вместо BeginThread, то есть шанс, что IsMultiThread будет равна False. А это в частности ведёт к тому, что менеджер памяти не будет использовать защиту ресурсов. Т.е. одновременный вызов функций перераспределения памяти из разных потоков может вызвать исключение.
2. Как насчёт защиты ресурсов в MessageLogProc? 3. И, кстати, try/finally здесь будет критично, т.к. любое исключение в любом потоке у вас немедленно завершает поток, но не освобождает критическую секцию. 4. Не проверяли - в каком месте именно вываливается AV? P.S. Да ну? XD Наверное, мне надо очки помощнее. Я вот смотрю на BeginThread и вижу: подготовка параметров, установка IsMultiThreaded, вызов CreateThread и... всё -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
| Coder |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 733 Регистрация: 13.12.2004 Репутация: 1 Всего: 11 |
Почему так происходит? По сути IsMultiThread я могу установить сам и спокойно пользоваться CreateThread(). Мне тогда не совсем понятна роль крит секций. Я ведь работаю с указателем на память где хранятся сообщения и в конкретный момент времени с ним должен работать ОДИН поток (перевыделить памяти, добавить сообщение). Сделаю.
Если есть такой механизм, это же не значит, что его нужно везде использовать где надо и не надо. Ф-ия AddLogMessage может загнуться на выделениях/перевыделениях памяти, но это можно обработать и "вручную". Отладчик на участок кода не показывает, а в дизассемблере - код не относящийся явно к проекту. Хотя покапать можно.
|
||||
|
|||||
| Riply |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Поимка AV (точнее: нахождение причины, а не места, где оно происходит) - одна из самых сложных операций. Сложнее, пожалуй, только "плавающая" ошибка. Допустим, мы собираемся тестировать этот код "в хвост и в гриву" У тебя есть уверенность, что N - незакрытых Handle`ов не повлияют на ход тестирования ? У меня нет. Уж не говоря о том, что их количество ограничено И гавное, определись с чем будем работать с BeginThread или CreateThread.
"Если на клетке со львом написано "Слон", то не верь глазам своим" (с) К. Прутков. (Писала по памяти, могла исказить) Именно из-за кажущейся простоты кода BeginThread, я и пыталась акцентировать на этом внимание, чтобы не было ползновений использовать CreateThread и вручную ставить IsMultiThreaded. Там есть "подводные камни". К сожалению не могу вспомнить, у кого вся эта кухня подробно расписана (сейчас проверила Рихтера - не нашла). Sorry. Может позже смогу привести ссылку. |
|||
|
||||
| CodeMonkey |
|
||||||||||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
Можете (на мой взгляд, может позже Riply ещё информации добавит). Совершенно верно. Вы своими критическими секциями защищаете свои глобальные переменные. Внимание, вопрос: кто будет защищать внутренние структуры менеджера памяти? Очевидно, сам менеджер памяти. Так вот, делать он этого не будет, если IsMultiThreaded не установлена. Так устроен мир. Делается это для экономии ресурсов в однопоточных приложениях - коих (пока) большинство.
Конкретно в этом случае - надо. Вы понимаете, что используя try/finally вы ГАРАНТИРУЕТЕ освобождение заблокированного ресурса. Как я уже сказал, без использования try/finally при возникновении любого исключения между Enter/LeaveCriticalSection вы навечно блокируете ресурс.
Как, позвольте, вы собрались обрабатывать вручную AV при перераспределении памяти не используя обработку исключений Delphi?
Попробуйте проставить по коду AddLogMessage вызовы OutputDebugString. Поймать их можно отладчиком Delphi или DebugView: http://technet.microsoft.com/en-us/sysinte...s/bb896647.aspx Например вот как-то так:
P.S.
Ну Рихтер говорил о аналогичных функциях в MS C++, а не в Delphi. Если же смотреть на исходный код BeginThread - то видно, что ничего дополнительного кроме установки IsMultiThreaded она не делает. Если были какие-то проблемы, которые решились сменой CreateThread на BeginThread, то они могут быть связаны (помимо IsMultiThreaded) с прототипом функции - он разный у BeginThread и CreateThread. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||||||||||
|
|||||||||||||
| Riply |
|
||||||
![]() Опытный ![]() ![]() Профиль Группа: Комодератор Сообщений: 572 Регистрация: 27.3.2007 Где: St. Petersburg Репутация: 21 Всего: 32 |
Ссылку, пока, не нашла, но рано или поздно найду. Чес. слово
Зато расскажу одну историю. Она не имеет отношения к теме, но показывает что не всегда можно безболезненно убирать "ненужные" вызовы. Имеем такую ф-ию:
Из нее видно, что ее вызов с параметром pSecAttr = nil сводится к вызову InitializeObjectAttributes. Т.е., казалось бы, в этом случае, их можно менять друг на друга. Ан нет. функция:
Но если в ней InitializeObjectAttributesEx заменить на InitializeObjectAttributes - эффет исчезал. Т.к. он (эффект) очень редко появлялся, я положила много времени на поимку бага. А он вот в чем: менялось "выравнивание" ObjAttr 32-х битную границу. Как результат, при некоторых "билдах" NtOpenSection начинала нецензурно ругаться. В итоге, для "надежного" использования InitializeObjectAttributesEx пришлось создавать такую структуру:
P.S. Если кто захочет воспроизвести эффект, ему придется набраться терпения, ибо он может зависить от взаиморасположения ф-ий и структур, номера билда и фазы луны P.P.S. Все это происходило под BDS 2006. Приведенный код выдергивался и чуть "правился на лету" - возможны ляпы Самый последий P.P.P.S Углубляться в обсуждение выравниваний не очень хочется, тем более ветка совсем не про это |
||||||
|
|||||||
| MetalFan |
|
||||
![]() Аццкий Сотона ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3815 Регистрация: 2.10.2006 Где: Moscow Репутация: 16 Всего: 128 |
очки по-мощнее пожалуй пригодятся... ибо:
CreateThread вызывается не с переданной ThreadFunc, а с борландовской оберткой ThreadWrapper ;) а в ней, на сколько я понимаю, еще корректно инициализируется обработка исключений. Это сообщение отредактировал(а) MetalFan - 11.7.2008, 21:08 -------------------- There are always someone smarter than you... |
||||
|
|||||
| CodeMonkey |
|
||||
|
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 16 Всего: 89 |
P.S.
Да, вы правы, наверное, зря я об этом не упомянул. Просто речь шла в контексте:
Т.е. касательно побочных эффектов в виде IsMultiThreaded. Поэтому я упомянул только действия до CreateThread. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||
|
|||||
![]()
|
| Правила форума "Delphi: WinAPI и системное программирование" | |
|
|
Запрещено: 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, bartram, MetalFan, bems, Poseidon, Rrader, Riply. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | Delphi: WinAPI и системное программирование | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |