![]() |
|
![]() ![]() ![]() |
|
Kirgston |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 792 Регистрация: 24.12.2007 Репутация: 2 Всего: 2 |
День добрый! Собственно задался вопросом "как же правильно синхронизировать формы (TFrom) в доступе между элементами". Вопрос начался с достаточно забавных вещей. Есть около 10 форм. Активно используется многопоточность. Есть вариант что при закрытии приложения поток попытается получить доступ к нужной ему форме. Собственно сразу получим AV. Сначала пытался проверить например
Потом понял что бесполезно т.к. указатель на форму может быть жив, а вся другая память уже освобождена. Проверки на Handle не дали никакого результата. Оказывается хендл тоже живёт сам по себе. Проверять свои переменные нет смысла т.к. если память освобождена то получаем AV. Нашёл конечно забавный метод проверять объекты ![]()
Но это вообще как то не по фен шую. Возможно кто-то подскажет как правильно синхронизировать работу между тредами <-> окнами и окнами <-> окнами ![]() |
||||
|
|||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 48 Всего: 223 |
Это называется RTFM. Потоки не могут напрямую обращаться к формам. Вся VCL расчитанна на обращение к себе из одного потока - своего собственного. Для синхронизации обращений из других потоков надо использовать TThread::Synchronize() (как то так, пишу по памяти) |
|||
|
||||
Kirgston |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 792 Регистрация: 24.12.2007 Репутация: 2 Всего: 2 |
Не "не могут" а не должны ;) А не должны потому что легко сделать Data Racing & Memory Corraption. Следовательно, просто ввели "обёртку" для синхронизации. Через что Вы там будете синхронизировать всем по барабану. Просто есть "стандартный набор джентльмена". И кто Вам сказал что я использую CreateThread/_beginthreadex? Используется тот же TThread. Может это Вам будет в диковинку, но формы могут быть удалены (вызван деструктор) скорее чем поток. Или наоборот. Поток начинает работу ещё до создания формы. Так что вызов Synchronize(&SaveData) внутри все равно будет иметь тот же доступ к MyForm->MyVar; Что в любом случае вызовет AV если формы нету или она частично удалена. Почему частично? Потому что после прохождения деструктора форма не с разу может быть удалена из памяти, это же чисто эвент. В реальный деструктор нас никто не пускает. Суть вопроса то в другом. Есть поток. Он отправляет сообщение (и да, он отправляет через Synchronize) главному окну. Главное окно (тут уже 1 поток) обрабатывает и хочет записать данные во второе окно. Второе окно уже завершило свою работу. Следовательно, обращение SecondForm->var = MainForm->var вызовет AV. Но в тот же момент проверка
Не даст ровно ничего. Т.к. большой вариант что указатель валиден, а данные внутри уже удалены. |
|||
|
||||
xvr |
|
||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 48 Всего: 223 |
Она не может быть 'частично' удалена.
Это чистый бред, уж извините. После деструктра формы уже нет, если ваша программа пытается к ней обратится после этого - это однозначно бага в вашей программе. Если вы имеете в виду, что после деструктора в памяти что то осталось, и вы пытаетесь к этому обратится - то это баг вдвойне ![]() ![]()
Все, что было отправленно через Synchronize будет вызываться безо всякой параллельности в главном потоке приложения. Деструкторы формы, которую удалили, вызывается там же, и так же строго последовательно. Отслеживайте уделение формы (прямо в деструкторе), и отключайте все callback'и, которые могут к ней обратится.
Если к окну добираются из SecondForm, обнулите его в деструкторе. В любом случае, при удалении любого объекта необходимо самому дерегистрировать все callback'и, которые были на него зарегистрированны (VCL этого за вас не сделает) |
||||||||
|
|||||||||
SVN74 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 740 Регистрация: 5.5.2008 Где: Комсомольск на Дн епре Репутация: 11 Всего: 18 |
Простейший способ, - написать свой класс, в котором создать список и критическую секцию, далее при создании новой формы добавлять указатель (на форму), а при удалении формы удалять указатель. Соответственно такой класс должен быть видим всем потокам и формам...
|
|||
|
||||
Kirgston |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 792 Регистрация: 24.12.2007 Репутация: 2 Всего: 2 |
Она может быть частично удалена Подозреваю что Вы путаете очистку памяти с деструктором формы. Простой пример. Вызывается деструктор. Во время его выполнения система посчитала что данному потоку уже хватит работать, останавливает его и передаёт управление другому потоку. В это время другой поток обращается к форме и получает на половину удалённый класс где половина объектов уже удалена, а половина ещё нет. С обычным приоритетом передача-прием управления это сотые секунды. Но разве это даёт 100% гарантию что никто(!) не попадёт в эти сотые секунды?
Если происходит обработка чего-либо и пользователь захотел остановить обработку и закрыть окно? Разве хорошо будет заставлять пользователя ждать? Категорически нет. Тем более что обработка в потоке и её можно остановить и без участия пользователя. По большому счёту должен использоваться пул потоков. Главный тред должен контролировать этот пул и должна быть общая таблица доступа. На данный момент такого ничего нет. Для быстрого фикса думал что у Builder'a есть в кармане ещё что то кроме Synchronize. Оказывается что нет. |
|||
|
||||
xvr |
|
||||||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 48 Всего: 223 |
При использовании Synchronize этого произойти не может в принципе. Удалять объект и/или работать с ним может только главный поток. Т.е. обращаться к удаляемому объекту в процессе его удаления никто не может - для обращения надо находится в главном потоке приложения, а он сейчас занят отработкой деструктора. Вы вообще в курсе, что делает Synchronize ?
Без проблем.
Вы путаете обработку (в отдельном потоке) и визуализацию ее результатов (в главном потоке через Synchronize).
Synchronize'а более чем достаточно - вы просто не умеете его готовить ![]() |
||||||||
|
|||||||||
Kirgston |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 792 Регистрация: 24.12.2007 Репутация: 2 Всего: 2 |
||||
|
||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 48 Всего: 223 |
||||
|
||||
Kirgston |
|
|||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 792 Регистрация: 24.12.2007 Репутация: 2 Всего: 2 |
Все таки я чего-то не понимаю. Разве любые коллбэки самого VCL не должны удалятся при разрушении формы?
Собственно то о чем я и говорил. Полуразрушенная форма которая вызывает коллбеки. При любом доступе куда угодно будет AV. http://prntscr.com/30tuzd После прохождения деструктора идёт вызов коллбека http://prntscr.com/30tw4i this данной формы. Собственно все в нуллах Это сообщение отредактировал(а) Kirgston - 15.3.2014, 00:55 |
|||
|
||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 48 Всего: 223 |
Нет конечно. Callback это просто указатель (точнее closure) на метод формы, который куда то присвоили. Ни VCL ни RTL не в курсе, что вы удалили форму, указатели по прежнему существуют и куда-то указывают (на мусор). VCL не занимается отслеживанием callback'ов и живости их форм. Сами регистрировали callback'и - сами и освобождайте Проверяйте в callback'е, что IdTCPServer1 не NULL. А лучше удалите сам callback в TServerCore при разрушении TIdTCPServer
Собственно об этом я тоже говорил - это ваша ошибка (как программиста конечно ![]() |
||||
|
|||||
Kirgston |
|
||||
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 792 Регистрация: 24.12.2007 Репутация: 2 Всего: 2 |
А теперь представьте многотысячный проект ![]() Если я явно не делаю new IdTCPServer1(размещаю визуальный контрол) то и в деструкторе мне не надо вызывать delete (TObject). За этим следит VCL. Пардон, а почему она тогда коллбеки не удаляет? Почему я за этим должен следить? Если бы я создавал объект в ручную - согласен. Но объект создаётся автоматически.
Если бы мы говорили о WinApi я бы согласился. Вручную создать объект. Вручную проследить за ним и удалить его. Да, так и надо. Но когда мы говорим о VCL которая якобы сама создаёт, сама разрушает и тут оказывается что она не чистит коллбеки? Разве об этом где то написано? |
||||
|
|||||
xvr |
|
||||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 48 Всего: 223 |
Все контролы, созданные самой VCL, живут до завершения приложения. И в конце все одним махом уничтожаются. При этом никакие вызовы асинхронных callback'ов просто не успевают возникнуть. Это вопрос не ко мне, а к фирме Borland - почему ее VCL не чистит callback'и ![]() ![]() Жизнь такая, тяжелая ![]()
Переходите на Qt - он чистит callback'и (они там организованны по другому). В 99% случаев чистка callback'ов не нужна, все и так работает. Но вполне может возникнуть тот 1% на котором может все сломаться. И это будет бага в VCL (или фича - если это описано в документации ![]() Вы форму, на которой лежал IdTCPServer1 вручную не удаляли? Если да - то это ваши грабли, если нет, то поздравляю - вы нашли багу в VCL (или скорее в TIdTCPServer ) PS. IdTCPServer1 было бы неплохо остановить перед завершением приложения, возможно оно у вас там и сломалось? |
||||
|
|||||
![]() ![]() ![]() |
Правила форума "С++ Builder" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C++ Builder | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |