![]() |
Модераторы: Poseidon, Snowy, bems, MetalFan |
![]() ![]() ![]() |
|
cemick |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 416 Регистрация: 6.7.2006 Где: Санкт-Петербург Репутация: 2 Всего: 6 |
Помогите разобратся, в процесс работы с потоками появился вопрос:
Что происходит с исключениями возбужденными в Tthread.Execute? Это сообщение отредактировал(а) cemick - 21.1.2009, 11:57 |
|||
|
||||
Matematik |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1027 Регистрация: 11.3.2006 Репутация: 17 Всего: 50 |
Поток завершается. Далее исключение можно отловить в событии Tthread.OnTerminate()
AFAIK, могу и ошибаться Это сообщение отредактировал(а) Matematik - 21.1.2009, 12:16 |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Всё верно.
+ ещё: Если свойство потока FreeOnTerminate ложно, то FatalException можно ещё прочитать после завершения потока откуда угодно - не обязательно из OnTerminate - пока объект потока не будет удалён. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
cemick |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 416 Регистрация: 6.7.2006 Где: Санкт-Петербург Репутация: 2 Всего: 6 |
Спасибо, помогли.
|
|||
|
||||
JSinx |
|
||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 12.12.2006 Репутация: нет Всего: 1 |
Странно, но у меня он равен nil, даже если возникало исключение, хотя при создании потока делаю FreeOnTerminate := false; Собственно мне нужно сделать обработку исключения из потока в главной форме, но при вызове raise у меня выводит кучу ошибок. т.е. вот такой код:
показывается еще раз окно с исключением, но потом уже совсем левые ошибки среды идут :(( |
||||
|
|||||
CodeMonkey |
|
||||||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Ать-ать (бьёт по рукам). Нельзя так. Могли бы и сами догадаться. Ведь обычно проверкой FatalException никто не заморачивается. Что это значит? А то, что по-умолчанию FatalException освобождается при удалении экземпляра TThead. С другой стороны, передавая экземпляр объекта в raise вы отдаёте управление сроком его жизни в рамки стандартного механизма исключений. Вот у вас и подрались два механизма. Правильный вариант (например):
Или (более вкусный, но грязный):
Добавлено через 4 минуты и 26 секунд Да, и кстати, возбуждать исключение в OnTerminate - крайне плохая идея. Если вы посмотрите на исходники TThread, то увидите:
Правильный вариант - сделать PostMessage в главную форму и в обработчике сообщения уже выполнить все свои грязные действия. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||||||
|
|||||||||
JSinx |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 12.12.2006 Репутация: нет Всего: 1 |
Увидел в примере какой то книжки вот такую обработку исключений в потоках:
Такой метод чемнить плох? Это сообщение отредактировал(а) JSinx - 8.2.2009, 17:31 |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Вроде бы в этом примере всё чисто и красиво.
-------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
SyCoDeR |
|
||||||||||
Новичок Профиль Группа: Участник Сообщений: 2 Регистрация: 6.2.2009 Репутация: нет Всего: нет |
Вступлю в дискуссию, ибо сам столкнулся с этой проблемой.
Тут вы видимо правы. Но вот это
не работает. И это
к сожалению тоже. Вообще совершенно любая попытка вызвать исключение в обработчике OnTerminate даже никак не связанное с исходным - например так
Вызывает падение программы. К сожалению, я не достаточно понимаю механизмы работы исключений - они достаточно сложны и абсолютно не документированы. А исходники написаны на ASM'е и, что хуже, опираются на недокументированные структуры данных. Если кто-нибудь в деталях объяснит, почему нельзя делать Raise в OnTerminate буду чрезвычайно благодарен. ![]() А пока - обходной путь:
|
||||||||||
|
|||||||||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Это баг в BeginThread. Система завершает всё приложение целиком, если в любом из его потоков возникает необработанное исключение. Системная функция CreateThread создаёт голый поток - вы обязаны сами заключать его код в try/except. BeginThread - это обёртка вокруг CreateThread, которая (помимо всего прочего) устанавливает фрейм исключения. По исключению в потоке должен вызываться обработчик исключений из SysUtils (если я правильно помню). Проблема в том, что в некоторых версиях Delphi это поведение реализовано некорректно. Ну а TThread просто использует BeginThread для вызова функции Execute. Поскольку OnTerminate вызывается вне глобального обработчика исключений на Execute, то и исключение в нём ничем не обрабатывается, кроме оболочки BeginThread. Которая, как уже было сказано, работает не всегда. Соответственно, ваше приложение может работать (показывая сообщение об ошибке) или вылетать - смотря в какой версии Delphi оно скомпилировано. +1 причина не делать ничего такого в OnTerminate ;) -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
SyCoDeR |
|
|||
Новичок Профиль Группа: Участник Сообщений: 2 Регистрация: 6.2.2009 Репутация: нет Всего: нет |
Во всяком сулчае в CodeGear™ Delphi® 2007 for Win32® Version 11.0.2902.10471 гарантированно вылетает.
Если кто-то может протестить на других версиях - вот код:
Обратите внимание, вылет в дебагер (разумеется, если в опциях включено Stop on delphi exceptions) на 'Вызываем новое исключение.' будет два!! раза. Собственно, я думаю, что это еще одно проявление той же ошибки. Разобраться бы еще какой... Это сообщение отредактировал(а) SyCoDeR - 6.2.2009, 14:49 |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Вам не всё ли равно? Возбуждение исключения в OnTerminate является плохой идеей. Я не знаю, какими ещё словами вам это сказать. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
MetalFan |
|
|||
![]() Аццкий Сотона ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3815 Регистрация: 2.10.2006 Где: Moscow Репутация: 62 Всего: 128 |
механизм вызова метода, назначенного св-ву OnTerminate можно подсмотреть в VCL.
код в OnTerminate через механизм синхронизации выполняется в контексте главного потока, НО обрабатываться исключение должно в контексте потока, вызвавшего этот метод через Synchronize да и вообще вызов необработанного исключения в любом потоке приведет к падению программы... Добавлено @ 16:36 кстати, знает ли общественность об еще одном механизме вызова метода в контексте осн.потока VCL? см. TThread.Queue Это сообщение отредактировал(а) MetalFan - 6.2.2009, 16:38 -------------------- There are always someone smarter than you... |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Кто-то уже подсуетился: QC Report #71230.
-------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
MetalFan |
|
|||
![]() Аццкий Сотона ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 3815 Регистрация: 2.10.2006 Где: Moscow Репутация: 62 Всего: 128 |
да это не бага, это нормальное и логичное поведение, если посмотреть код ThreadWrapper в classes.pas
-------------------- There are always someone smarter than you... |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
Так я и не спорил
![]() -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
JSinx |
|
||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 71 Регистрация: 12.12.2006 Репутация: нет Всего: 1 |
Попытаюсь подвести итог
![]()
и "вариант из книги"
Какой же из них тогда более правильный? P.S. За "вариант из книги" почему-то проминусили ![]() |
||||
|
|||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 38 Всего: 89 |
>>> Какой же из них тогда более правильный?
Оба правильные. Просто работают по-разному. Хотя сильно принципиальной разницы между ними нет. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
cemick |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 416 Регистрация: 6.7.2006 Где: Санкт-Петербург Репутация: 2 Всего: 6 |
На правах автора темы подниму из небытия. Интересно, что если в не основном потоке будет
try // Код потока except // Сохраняем исключение в поле FExceptionObject := AcquireExceptionObject(); end; А в главном потоке сделаем: raise FThread.ExceptionObject ; Как мне видеться такой код чист и должен работать или я ошибаюсь? |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Delphi: Общие вопросы" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |