![]() |
|
![]() ![]() ![]() |
|
gAlexKo |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 72 Регистрация: 23.3.2011 Репутация: нет Всего: нет |
Читал я конечно об обязательном использовании Synchonize, но возможно я понял что-то не так.
У меня есть программа, на форме есть Panel1 и Memo1. Я создаю поток который должен писать в Panel1 и Memo1. Сам основной поток VCL ничего в Panel1 и Memo1 не пишет. Тогда я подумал, что раз элементы вывода используются только созданным потоком, то и синхронизировать тут нечего - просто нет конфликта. Убрал я Synchronize и вывожу данные на Panel1 и Memo1 прямо из потока. Ну типа пишу в потоке что Form1->Panel1->Caption = ... Все работает и не глючит. Какие неприятности могут меня ожидать? Напоминаю, что в компоненты Panel1 и Memo1 пишет только поток TThread. Это сообщение отредактировал(а) gAlexKo - 2.2.2015, 12:22 |
|||
|
||||
SVN74 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 740 Регистрация: 5.5.2008 Где: Комсомольск на Дн епре Репутация: 11 Всего: 18 |
Застопорите основной поток и получите ошибку... В VCL только основной поток имеет неразделимые полномочия, другие же потоки всего лишь выпрашивают у основного потока через Synchonize доступ к компоненту на определенный квант времени. |
|||
|
||||
gAlexKo |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 72 Регистрация: 23.3.2011 Репутация: нет Всего: нет |
Проблема возникла (CBuilder6) после такой ситуации - в главной форме я создал новую нитку TThread. Если я работаю напрямую без Synchonize то нитка работает. Стоит мне начать работать выводом на форму правильно через Synchonize - нитка останавливается, точнее если я двигаю по форме курсором мыши, то нитка работает, но только пока мышь двигается. Путем усечения проекта я выяснил, что дело в функции одной моей Dll_1, в которой есть функция с вызовом функции из другой dll_2. Если это место (внутри dll_1) закоментировать, то Synchonize начинает работать. Даже не знаю где копать дальше. Стоит мне просто создать в главной форме объект из dll_1 как новая нитка начинает затыкаться. Стоит мне закоментировать этот объект нитка начинает работать нормально. |
|||
|
||||
Romikgy |
|
|||
![]() Любитель-программер ![]() ![]() ![]() ![]() Профиль Группа: Участник Клуба Сообщений: 7326 Регистрация: 11.5.2005 Где: Porto Franco Odes sa Репутация: 11 Всего: 146 |
неправильная работа синхронизаций потоков и использование dll
PS точнее никто не подскажет , ибо ошибки в коде! -------------------- Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. ![]() |
|||
|
||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 26 Всего: 459 |
Это скорее всего ошибки в проектировании. Неправильно реализована синхронизация. На лицо избыточная синхронизация. Дело в том, что если внутри функции Synchronize вызвать функцию SendMessage или что-то аналогичное блокирующее исполнение, то возникает дедлок. Функция Synchronize блокирует главный поток, а он занимается обработкой сообщений, а функция SendMessage не возвращает управление пока сообщение не будет обработано. Возможно, у вас вместо SendMessage есть другой блокирующий механизм, но суть остается той же - дедлок. В таких ситуациях нужно ликвидировать избыточную синхронизацию. Например сделать свое сообщение типа WM_USER +1 и послать его форме через PostMessage. Внутри обработчика сообщения WM_USER +1 код будет выполняться в главном потоке, но функция PostMessage не блокирует вызывающий поток. В некоторых случаях PostMessage не допустимо использовать по причине необходимости ожидания ответа. В этих случаях нужно проверить так ли вам нужно исполнение кода в главном потоке. Ведь можно использовать критические секции. Этот механизм позволяет обращаться к общим данным из разных потоков, но синхронизация не приводит к тому, что некоторый участок кода выполняется в главном потоке. Если все же ни критические секции ни PostMessage не помогает, вам может помочь вызов Application->ProcessMessages() внутри Synchronize (во время ожидания ответа) . Т.е. вы хотя и заблокировали оба потока, но все равно ведете обработку сообщений. Если дело было в сообщениях, то Application->ProcessMessages() обработает нужные сообщения, и вероятно, будет получен сигнал разрешающий выход из Synchronize . Ну и последний самый маловероятный вариант. Вы загрузили главный поток по максимуму, так что он редко переходит в OnIdle (в нем вызывается Synchronize ). В этом случае лучше проверить правильно ли вы выбрали профессию ![]() -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
gAlexKo |
|
|||
Шустрый ![]() Профиль Группа: Участник Сообщений: 72 Регистрация: 23.3.2011 Репутация: нет Всего: нет |
Спасибо насчет совета о профессии. Посмотрим что вы сможете сказать по существу. Я максимально урезал проект (фактически до нескольких строк) и вы увидите, что дело не в том, как я реализовал нитку и синхронизацию. Проблема сложнее чем вы думаете. Смысл в том, что если убрать из заголовка формы стркутуру из dll (ACP_HEAD), то нитка начинает работать. Вопрос только в чем дело. В DL_server_play.cpp кнопка запуска В DL_server_thread.cpp сама нитка Это сообщение отредактировал(а) gAlexKo - 4.2.2015, 13:23 Присоединённый файл ( Кол-во скачиваний: 8 ) ![]() |
|||
|
||||
SVN74 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 740 Регистрация: 5.5.2008 Где: Комсомольск на Дн епре Репутация: 11 Всего: 18 |
Можно просто (без синхронизации) использовать PostMessage на компоненты формы, если конечно это связано с банальным выводом.
|
|||
|
||||
Alexeis |
|
||||||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 26 Всего: 459 |
О_о вы читаете посты снизу вверх? Код весьма любопытный
Suspend - замораживает поток, Terminate выставляет флаг потоку завершить работу, но прочитать его поток не в силах потому что спит. Имеем зависший главный поток при попытке уничтожить дополнительный (вероятно отлипает по таймауту). Что на счет кода
Не исключаю, что тут задействованы сообщения. У класса TMemo свой класс для Lines называется TMemoLines. Точную реализацию его не помню, но он является оберткой вокруг WinApi окна EDIT Обмен с окнами типа EDIT осуществляется путем отсылки сообщений WM_SETTEXT / EM_REPLACESEL более подробно можно разобраться если изучать код VCL или соответствующую статью MSDN https://msdn.microsoft.com/en-us/library/wi...retrieving_text Решение этой проблемы во 2м абзаце. Нужно изменить порядок общения. Дополнительный поток лишь уведомляет главный, о том, что необходимо обновить свое состояние - PostMessage(..,WM_USER+X, <код уведомления или указатель на данные>, ...); Главный поток обрабатывая WM_USER+X вычитывает данные из потока. Тут возможно потребуется критическая секция, если оба потока могут одновременно обращаться к общей памяти. Если процесс конвейерный, т.е. доп поток после обработки первого блока переходит ко второму, то критическая секция вовсе не нужна. Это сообщение отредактировал(а) Alexeis - 4.2.2015, 17:32 -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
||||||
|
|||||||
Alexeis |
|
|||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 26 Всего: 459 |
Хотя на счет SF=NULL; я, наверное, неправ. Скорее всего SF не является умным указателем, поэтому дополнительный поток просто зависнет не завершившись, а главный поток проскочит это место. Чтобы код худо бедно заработал достаточно просто убрать SF->Suspend();
-------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
|||
|
||||
gAlexKo |
|
||||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 72 Регистрация: 23.3.2011 Репутация: нет Всего: нет |
Насчет Suspend() при выключении нитки вы правы - это не нужно, это остаток от одного из танцев с бубном. Но похоже вы не поняли главную проблему. Я же говорю, что дело тут не в том как синхронизировать, а в том, что мистическим образом подключенные библиотеки dll не дают работать нитке(!). Стоит убрать библиотеки(обратите внимание, что они в сущности никак не задействованы), то нитка отлично начинает работать. Чтобы не быть госолословным посылаю тот же проект, откуда выкинуты все линкованные библиотеки, а код нитки, ее запуска, обращения к Synrnonize прежние. Словом дело тут в тонкостях линковки и влияниях подключенных (и даже неиспользуемых) DLL на созданную нитку. Это сообщение отредактировал(а) gAlexKo - 5.2.2015, 08:46 Присоединённый файл ( Кол-во скачиваний: 2 ) ![]() |
||||||
|
|||||||
Alexeis |
|
||||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 26 Всего: 459 |
Они не задействованы только на первый взгляд. Три библиотеки написаны на C++ Builder 6й версии и 2е из них скомпилированны с пакетами. Это значит что они вполне себе инициализируются стандартными средствами VCL. __fastcall System::UnregisterModule(System::TLibModule *) __fastcall System::RegisterModule(System::TLibModule *) А значит определенные действия могут производить сами. Заводить таймеры, устанавливать калбеки и т.д. Та, которая подозрительная, работает с потоками, или по крайней мере имеет средства защиты от многопоточного вызова. DeleteCriticalSection EnterCriticalSection InterlockedExchange EnumThreadWindows Это хорошо, если без Dll работает, но боюсь что решение проблемы остается тем же. Сам по себе механизм Synchronize потока является малоэффективным. Чтобы он сработал, должна сработать ветка OnIdle объекта Application. Думаю ключевым является это место
Вероятно дело не в 100% загрузке проца, а в фризах главного потока. Симптомы такие, как-будто кто-то усыпляет главный поток приложения до тех пор пока не приходит сообщения. Такая функция есть в Windows, называется MsgWaitForMultipleObjects, но ее следов не обнаружено ни в одной Dll. Дело в том, что эта функция гробит механизм весь механизм фоновой обработки Application в том числе и Synchronize. Аналогичный эффект можно получить функцией GetMessage, или PeekMessage + Sleep, но ничего из перечисленного нет в секциях импорта dll. Головоломка, конечно, интересная, но я бы не терял время и сделал синхронизацию сообщениями, ведь при движении мыши все работает, значит сообщения Windows прерывают фриз. В любом случае сообщения Windows имеют выше приоритет обработки чем фоновые задачи, поэтому такой механизм синхронизации всегда будет более отзывчивым. -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
||||
|
|||||
xvr |
|
|||
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 48 Всего: 223 |
Кроме уже упомянутых Alexeis вызовов инициализации пакета, стоит отметить, что ваша - не структура, а класс с конструктором. Так что как минимум еще вызывается конструктор этого самого ACP_HEAD. Так что постулат о 'незадействованности' неверен уже дважды ![]() |
|||
|
||||
gAlexKo |
|
||||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 72 Регистрация: 23.3.2011 Репутация: нет Всего: нет |
Так как это моё, то могут сказать, что в конструкторе ACP_HEAD делается только очистка памяти структуры. Переменные в структуре выделяются без всяких new (это тянется с тех времен когда это было на Си). Добавлено @ 17:34
Я решил попробовать использовать критическую секцию TCriticalSection и мне очень понравилось. Типа идея простая - на период вывода нить блокирует все другие нити, в том числе и VCL. Я сделал новый короткий образец (см в архиве). Единственная засада которую я не смог приодолеть. ;-) Если я (после запуска нити) выключаю нитку кнопкой, а затем закрываю форму выходя из программы все работает. Если я закрываю форму с работаюшей нитью (крестом формы), то вылетает ошибка. Как я не трахался, но я не смог найти как закрыть форму с работающей ниткой. Что я делаю не так в CloseForm? Задача вроде тривиальная, но... не выходит. Это сообщение отредактировал(а) gAlexKo - 5.2.2015, 17:37 Присоединённый файл ( Кол-во скачиваний: 2 ) ![]() |
||||||
|
|||||||
Alexeis |
|
||||
![]() Амеба ![]() Профиль Группа: Админ Сообщений: 11743 Регистрация: 12.10.2005 Где: Зеленоград Репутация: 26 Всего: 459 |
Критическая секция сама по себе не поможет. Программист не знает всех мест где VCL обращается к Memo, поэтому невозможно изолировать эти операции от своего кода. Можно только в сообщении, поскольку мы точно знаем, что VCL поток занят обработкой сообщений и он точно ничего не делает в данный момент.
Это от того что используется упрощенный способ завершения потока. Нужно убрать автоудаление потока и при завершении программы сначала вызвать Terminate, затем WaitFor, а потом уже можно смело делать ему delete -------------------- Vit вечная память. Обсуждение действий администрации форума производятся только в этом форуме гениальность идеи состоит в том, что ее невозможно придумать |
||||
|
|||||
gAlexKo |
|
||||||
Шустрый ![]() Профиль Группа: Участник Сообщений: 72 Регистрация: 23.3.2011 Репутация: нет Всего: нет |
Но ведь смысл использования TCriticalSection это создать один глобальный объект для всех нитей. Каждая из нитей может получить экслюзивное исполнение внутри секции. Ничего знать не нужно, но можно быть уверенным, что конфликта нитей не будет (в том числе VCL). -----Beginning of the citation----- Use TCriticalSection to safeguard operations that may be disrupted if another thread executes certain sections of code before the operation is completed. Critical sections work like gates that allow only a single thread to enter at a time. Because they block the execution of other threads..... Critical sections must be GLOBALl in scope so that they are available to all threads. In every thread, any action that could interfere with the operations safeguarded by the critical section should only take place after calling the Acquire or Enter method. ----- The end of the citation ----- Таким образом
не должен быть в конфликте с VCL? Это сообщение отредактировал(а) gAlexKo - 6.2.2015, 08:28 |
||||||
|
|||||||
![]() ![]() ![]() |
Правила форума "С++ Builder" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Rrader. |
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | C++ Builder | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |