Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Синхронизация форм 
:(
    Опции темы
Kirgston
Дата 2.3.2014, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 792
Регистрация: 24.12.2007

Репутация: 2
Всего: 2



День добрый! Собственно задался вопросом "как же правильно синхронизировать формы (TFrom) в доступе между элементами". Вопрос начался с достаточно забавных вещей. Есть около 10 форм. Активно используется многопоточность. Есть вариант что при закрытии приложения поток попытается получить доступ к нужной ему форме. Собственно сразу получим AV. Сначала пытался проверить например
Код

if (MyForm)
...


Потом понял что бесполезно т.к. указатель на форму может быть жив, а вся другая память уже освобождена. Проверки на Handle не дали никакого результата. Оказывается хендл тоже живёт сам по себе. Проверять свои переменные нет смысла т.к. если память освобождена то получаем AV. Нашёл конечно забавный метод проверять объекты smile

Код

if (MyForm->Label1)


Но это вообще как то не по фен шую. Возможно кто-то подскажет как правильно синхронизировать работу между тредами <-> окнами и окнами <-> окнами smile
PM MAIL   Вверх
xvr
Дата 3.3.2014, 13:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Kirgston @  2.3.2014,  22:55 Найти цитируемый пост)
Активно используется многопоточность. Есть вариант что при закрытии приложения поток попытается получить доступ к нужной ему форме.

Это называется RTFM. Потоки не могут напрямую обращаться к формам. Вся VCL расчитанна на обращение к себе из одного потока - своего собственного. Для синхронизации обращений из других потоков надо использовать TThread::Synchronize() (как то так, пишу по памяти)

PM MAIL   Вверх
Kirgston
Дата 3.3.2014, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 792
Регистрация: 24.12.2007

Репутация: 2
Всего: 2



Цитата(xvr @ 3.3.2014,  13:29)
Цитата(Kirgston @  2.3.2014,  22:55 Найти цитируемый пост)
Активно используется многопоточность. Есть вариант что при закрытии приложения поток попытается получить доступ к нужной ему форме.

Это называется RTFM. Потоки не могут напрямую обращаться к формам. Вся VCL расчитанна на обращение к себе из одного потока - своего собственного. Для синхронизации обращений из других потоков надо использовать TThread::Synchronize() (как то так, пишу по памяти)

Не "не могут" а не должны ;)

А не должны потому что легко сделать Data Racing & Memory Corraption. Следовательно, просто ввели "обёртку" для синхронизации. Через что Вы там будете синхронизировать всем по барабану. Просто есть "стандартный набор джентльмена".

И кто Вам сказал что я использую CreateThread/_beginthreadex?

Используется тот же TThread. Может это Вам будет в диковинку, но формы могут быть удалены (вызван деструктор) скорее чем поток. Или наоборот. Поток начинает работу ещё до создания формы. Так что вызов Synchronize(&SaveData) внутри все равно будет иметь тот же доступ к MyForm->MyVar; Что в любом случае вызовет AV если формы нету или она частично удалена. Почему частично? Потому что после прохождения деструктора форма не с разу может быть удалена из памяти, это же чисто эвент. В реальный деструктор нас никто не пускает.

Суть вопроса то в другом. Есть поток. Он отправляет сообщение (и да, он отправляет через Synchronize) главному окну. Главное окно (тут уже 1 поток) обрабатывает и хочет записать данные во второе окно. Второе окно уже завершило свою работу. Следовательно, обращение SecondForm->var = MainForm->var вызовет AV. Но в тот же момент проверка

Код

if (SecondForm)
SecondForm->var = MainForm->var


Не даст ровно ничего. Т.к. большой вариант что указатель валиден, а данные внутри уже удалены.
PM MAIL   Вверх
xvr
Дата 4.3.2014, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Kirgston @  3.3.2014,  16:48 Найти цитируемый пост)
Что в любом случае вызовет AV если формы нету или она частично удалена.

Она не может быть 'частично' удалена. 
Цитата(Kirgston @  3.3.2014,  16:48 Найти цитируемый пост)
Почему частично? Потому что после прохождения деструктора форма не с разу может быть удалена из памяти, это же чисто эвент. 

Это чистый бред, уж извините. После деструктра формы уже нет, если ваша программа пытается к ней обратится после этого - это однозначно бага в вашей программе. Если вы имеете в виду, что после деструктора в памяти что то осталось, и вы пытаетесь к этому обратится - то это баг вдвойне  smile Классическое обращение по освобожденной динамической памяти, и это бывает где угодно, а не только в MT программах  smile 
Цитата(Kirgston @  3.3.2014,  16:48 Найти цитируемый пост)
Есть поток. Он отправляет сообщение (и да, он отправляет через Synchronize) главному окну. Главное окно (тут уже 1 поток) обрабатывает и хочет записать данные во второе окно. Второе окно уже завершило свою работу.

Все, что было отправленно через Synchronize будет вызываться безо всякой параллельности в главном потоке приложения. Деструкторы формы, которую удалили, вызывается там же, и так же строго последовательно. Отслеживайте уделение формы (прямо в деструкторе), и отключайте все callback'и, которые могут к ней обратится.

Цитата(Kirgston @  3.3.2014,  16:48 Найти цитируемый пост)
Второе окно уже завершило свою работу. Следовательно, обращение SecondForm->var = MainForm->var вызовет AV. 

Если к окну добираются из SecondForm, обнулите его в деструкторе.

В любом случае, при удалении любого объекта необходимо самому дерегистрировать все callback'и, которые были на него зарегистрированны (VCL этого за вас не сделает)

PM MAIL   Вверх
SVN74
Дата 4.3.2014, 20:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 740
Регистрация: 5.5.2008
Где: Комсомольск на Дн епре

Репутация: 11
Всего: 18



Простейший способ, - написать свой класс, в котором создать список и критическую секцию, далее при создании новой формы добавлять указатель (на форму), а при удалении формы удалять указатель. Соответственно такой класс должен быть видим всем потокам и формам...
PM MAIL WWW   Вверх
Kirgston
Дата 4.3.2014, 23:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 792
Регистрация: 24.12.2007

Репутация: 2
Всего: 2



Цитата(xvr @  4.3.2014, 09:45 Найти цитируемый пост)
Она не может быть 'частично' удалена. 

Она может быть частично удалена

Подозреваю что Вы путаете очистку памяти с деструктором формы. Простой пример. Вызывается деструктор. Во время его выполнения система посчитала что данному потоку уже хватит работать, останавливает его и передаёт управление другому потоку. В это время другой поток обращается к форме и получает на половину удалённый класс где половина объектов уже удалена, а половина ещё нет. С обычным приоритетом передача-прием управления это сотые секунды. Но разве это даёт 100% гарантию что никто(!) не попадёт в эти сотые секунды?

Цитата(xvr @  4.3.2014, 09:45 Найти цитируемый пост)
После деструктра формы уже нет, если ваша программа пытается к ней обратится после этого - это однозначно бага в вашей программе.

Если происходит обработка чего-либо и пользователь захотел остановить обработку и закрыть окно? Разве хорошо будет заставлять пользователя ждать? Категорически нет. Тем более что обработка в потоке и её можно остановить и без участия пользователя.

По большому счёту должен использоваться пул потоков. Главный тред должен контролировать этот пул и должна быть общая таблица доступа. На данный момент такого ничего нет. Для быстрого фикса думал что у Builder'a есть в кармане ещё что то кроме Synchronize. Оказывается что нет.
PM MAIL   Вверх
xvr
Дата 5.3.2014, 09:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Kirgston @  4.3.2014,  23:51 Найти цитируемый пост)
 Во время его выполнения система посчитала что данному потоку уже хватит работать, останавливает его и передаёт управление другому потоку. В это время другой поток обращается к форме и получает на половину удалённый класс где половина объектов уже удалена, а половина ещё нет. 

При использовании Synchronize этого произойти не может в принципе. Удалять объект и/или работать с ним может только главный поток. Т.е. обращаться к удаляемому объекту в процессе его удаления никто не может - для обращения надо находится в главном потоке приложения, а он сейчас занят отработкой деструктора. Вы вообще в курсе, что делает Synchronize  ?

Цитата(Kirgston @  4.3.2014,  23:51 Найти цитируемый пост)
Если происходит обработка чего-либо и пользователь захотел остановить обработку и закрыть окно?

Без проблем. 
Цитата(Kirgston @  4.3.2014,  23:51 Найти цитируемый пост)
Тем более что обработка в потоке и её можно остановить и без участия пользователя.

Вы путаете обработку (в отдельном потоке) и визуализацию ее результатов (в главном потоке через Synchronize). 
Цитата(Kirgston @  4.3.2014,  23:51 Найти цитируемый пост)
Для быстрого фикса думал что у Builder'a есть в кармане ещё что то кроме Synchronize. 

Synchronize'а более чем достаточно - вы просто не умеете его готовить  smile 

PM MAIL   Вверх
Kirgston
Дата 12.3.2014, 16:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 792
Регистрация: 24.12.2007

Репутация: 2
Всего: 2



Цитата(xvr @  5.3.2014,  09:13 Найти цитируемый пост)
Synchronize'а более чем достаточно - вы просто не умеете его готовить   

Вполне возможно. Спасибо, буду ковырять
PM MAIL   Вверх
xvr
Дата 13.3.2014, 10:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Kirgston @  12.3.2014,  16:26 Найти цитируемый пост)
Вполне возможно. Спасибо, буду ковырять 

Посмотрите эту статью.

PM MAIL   Вверх
Kirgston
Дата 15.3.2014, 00:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 792
Регистрация: 24.12.2007

Репутация: 2
Всего: 2



Все таки я чего-то не понимаю. Разве любые коллбэки самого VCL не должны удалятся при разрушении формы?

Собственно то о чем я и говорил. Полуразрушенная форма которая вызывает коллбеки. При любом доступе куда угодно будет AV.

http://prntscr.com/30tuzd
После прохождения деструктора идёт вызов коллбека

http://prntscr.com/30tw4i
this данной формы. Собственно все в нуллах

Это сообщение отредактировал(а) Kirgston - 15.3.2014, 00:55
PM MAIL   Вверх
xvr
Дата 15.3.2014, 08:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Kirgston @  15.3.2014,  00:53 Найти цитируемый пост)
Разве любые коллбэки самого VCL не должны удалятся при разрушении формы?

Нет конечно. Callback это просто указатель (точнее closure) на метод формы, который куда то присвоили. Ни VCL ни RTL не в курсе, что вы удалили форму, указатели по прежнему существуют и куда-то указывают (на мусор). VCL не занимается отслеживанием callback'ов и живости их форм.  Сами регистрировали callback'и - сами и освобождайте

Цитата(Kirgston @  15.3.2014,  00:53 Найти цитируемый пост)
После прохождения деструктора идёт вызов коллбека

Проверяйте в callback'е, что IdTCPServer1 не NULL. А лучше удалите сам callback в TServerCore при разрушении TIdTCPServer

Цитата(Kirgston @  15.3.2014,  00:53 Найти цитируемый пост)
Собственно то о чем я и говорил. Полуразрушенная форма которая вызывает коллбеки.

Собственно об этом я тоже говорил - это ваша ошибка (как программиста конечно  smile  )

PM MAIL   Вверх
Kirgston
Дата 15.3.2014, 10:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 792
Регистрация: 24.12.2007

Репутация: 2
Всего: 2



Цитата(xvr @  15.3.2014,  08:38 Найти цитируемый пост)
Проверяйте в callback'е, что IdTCPServer1 не NULL. А лучше удалите сам callback в TServerCore при разрушении TIdTCPServer

А теперь представьте многотысячный проект smile 

Если я явно не делаю new IdTCPServer1(размещаю визуальный контрол) то и в деструкторе мне не надо вызывать delete (TObject). За этим следит VCL. Пардон, а почему она тогда коллбеки не удаляет? Почему я за этим должен следить? Если бы я создавал объект в ручную - согласен. Но объект создаётся автоматически.

Цитата(xvr @  15.3.2014, 08:38 Найти цитируемый пост)
Собственно об этом я тоже говорил - это ваша ошибка (как программиста конечно )

Если бы мы говорили о WinApi я бы согласился. Вручную создать объект. Вручную проследить за ним и удалить его. Да, так и надо. Но когда мы говорим о VCL которая якобы сама создаёт, сама разрушает и тут оказывается что она не чистит коллбеки? Разве об этом где то написано?
PM MAIL   Вверх
xvr
Дата 15.3.2014, 16:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 48
Всего: 223



Цитата(Kirgston @  15.3.2014,  10:53 Найти цитируемый пост)
Если я явно не делаю new IdTCPServer1(размещаю визуальный контрол) то и в деструкторе мне не надо вызывать delete (TObject).

Все контролы, созданные самой VCL, живут до завершения приложения. И в конце все одним махом уничтожаются. При этом никакие вызовы асинхронных callback'ов просто не успевают возникнуть. 

Цитата(Kirgston @  15.3.2014,  10:53 Найти цитируемый пост)
 Пардон, а почему она тогда коллбеки не удаляет?
Это вопрос не ко мне, а к фирме Borland - почему ее VCL не чистит callback'и  smile Дизайн VCL такой  smile 

Цитата(Kirgston @  15.3.2014,  10:53 Найти цитируемый пост)
Почему я за этим должен следить? 
Жизнь такая, тяжелая  smile 

Цитата(Kirgston @  15.3.2014,  10:53 Найти цитируемый пост)
 Но когда мы говорим о VCL которая якобы сама создаёт, сама разрушает и тут оказывается что она не чистит коллбеки?

Переходите на Qt - он чистит callback'и (они там организованны по другому).

Цитата(Kirgston @  15.3.2014,  10:53 Найти цитируемый пост)
Разве об этом где то написано? 
В 99% случаев чистка callback'ов не нужна, все и так работает. Но вполне может возникнуть тот 1% на котором может все сломаться. И это будет бага в VCL (или фича - если это описано в документации  smile )

Вы форму, на которой лежал IdTCPServer1 вручную не удаляли? Если да - то это ваши грабли, если нет, то поздравляю - вы нашли багу в VCL (или скорее в TIdTCPServer )

PS. IdTCPServer1 было бы неплохо остановить перед завершением приложения, возможно оно у вас там и сломалось?

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C++ Builder | Следующая тема »


 




[ Время генерации скрипта: 0.1318 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.