Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Всегда ли нужен Synchronize для TThread, Synchronize и TThread 
:(
    Опции темы
gAlexKo
Дата 2.2.2015, 12:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 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
PM MAIL   Вверх
SVN74
Дата 2.2.2015, 13:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Цитата(gAlexKo @  2.2.2015,  12:02 Найти цитируемый пост)
 Все работает и не глючит.  Какие неприятности могут меня ожидать?

Застопорите основной поток и получите ошибку...
В VCL только основной поток имеет неразделимые полномочия, другие же потоки всего лишь выпрашивают у основного потока через Synchonize доступ к компоненту на определенный квант времени.
 

PM MAIL WWW   Вверх
gAlexKo
Дата 3.2.2015, 17:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(SVN74 @ 2.2.2015,  13:06)
Цитата(gAlexKo @  2.2.2015,  12:02 Найти цитируемый пост)
 Все работает и не глючит.  Какие неприятности могут меня ожидать?

Застопорите основной поток и получите ошибку...
В VCL только основной поток имеет неразделимые полномочия, другие же потоки всего лишь выпрашивают у основного потока через Synchonize доступ к компоненту на определенный квант времени.

Проблема возникла (CBuilder6) после такой ситуации - в главной форме я создал новую нитку TThread.
Если я работаю напрямую без Synchonize то нитка работает. Стоит мне начать работать выводом на форму правильно через Synchonize - нитка останавливается, точнее если я двигаю по форме курсором мыши, то нитка работает, но только пока мышь двигается.

Путем усечения проекта я выяснил, что дело в функции одной моей Dll_1, в которой есть функция с вызовом функции из другой dll_2. Если это место (внутри dll_1) закоментировать, то Synchonize начинает работать. Даже не знаю где копать дальше. Стоит мне просто создать в главной форме объект из dll_1 как новая нитка начинает затыкаться. Стоит мне закоментировать этот объект нитка начинает работать нормально.
PM MAIL   Вверх
Romikgy
Дата 3.2.2015, 21:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

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



неправильная работа синхронизаций потоков и использование dll 

PS точнее никто не подскажет , ибо ошибки в коде!


--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
Alexeis
Дата 4.2.2015, 11:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



Цитата(gAlexKo @  3.2.2015,  18:08 Найти цитируемый пост)
 Стоит мне начать работать выводом на форму правильно через Synchonize - нитка останавливается, точнее если я двигаю по форме курсором мыши, то нитка работает, но только пока мышь двигается.

  Это скорее всего ошибки в проектировании. Неправильно реализована синхронизация. На лицо избыточная синхронизация. Дело в том, что если внутри функции Synchronize вызвать функцию SendMessage или что-то аналогичное блокирующее исполнение, то возникает дедлок. Функция Synchronize блокирует главный поток, а он занимается обработкой сообщений, а функция SendMessage не возвращает управление пока сообщение не будет обработано.
  Возможно, у вас вместо SendMessage есть другой блокирующий механизм, но суть остается той же - дедлок.

  В таких ситуациях нужно ликвидировать избыточную синхронизацию. Например сделать свое сообщение типа WM_USER +1 и послать его форме через PostMessage. Внутри обработчика сообщения WM_USER +1 код будет выполняться в главном потоке, но функция PostMessage не блокирует вызывающий поток. 

  В некоторых случаях PostMessage не допустимо использовать по причине необходимости ожидания ответа. В этих случаях нужно проверить так ли вам нужно исполнение кода в главном потоке. Ведь можно использовать критические секции. Этот механизм позволяет обращаться к общим данным из разных потоков, но синхронизация не приводит к тому, что некоторый участок кода выполняется в главном потоке.

  Если все же ни критические секции ни PostMessage не помогает, вам может помочь вызов Application->ProcessMessages() внутри Synchronize (во время ожидания ответа) . Т.е. вы хотя и заблокировали оба потока, но все равно ведете обработку сообщений. Если дело было в сообщениях, то Application->ProcessMessages() обработает нужные сообщения, и вероятно, будет получен сигнал разрешающий выход из Synchronize .

 Ну и последний самый маловероятный вариант. Вы загрузили главный поток по максимуму, так что он редко переходит в OnIdle (в нем вызывается Synchronize ). В этом случае лучше проверить правильно ли вы выбрали профессию  smile 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
gAlexKo
Дата 4.2.2015, 13:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Alexeis @ 4.2.2015,  11:41)
Цитата(gAlexKo @  3.2.2015,  18:08 Найти цитируемый пост)
 Стоит мне начать работать выводом на форму правильно через Synchonize - нитка останавливается, точнее если я двигаю по форме курсором мыши, то нитка работает, но только пока мышь двигается.

  Это скорее всего ошибки в проектировании. Неправильно реализована синхронизация. На лицо избыточная 
<skipped>
чше проверить правильно ли вы выбрали профессию  smile

Спасибо насчет совета о профессии. Посмотрим что вы сможете сказать по существу. Я максимально урезал проект (фактически до нескольких строк) и вы увидите, что дело не в том, как я реализовал нитку и синхронизацию. Проблема сложнее чем вы думаете.  Смысл в том, что если убрать из заголовка формы стркутуру из dll (ACP_HEAD), то нитка начинает работать. Вопрос только в чем дело.

В DL_server_play.cpp кнопка запуска
В DL_server_thread.cpp сама нитка


Это сообщение отредактировал(а) gAlexKo - 4.2.2015, 13:23

Присоединённый файл ( Кол-во скачиваний: 8 )
Присоединённый файл  thread_problem.zip 878,68 Kb
PM MAIL   Вверх
SVN74
Дата 4.2.2015, 15:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Можно просто (без синхронизации) использовать  PostMessage на компоненты формы, если конечно это связано с банальным выводом. 
PM MAIL WWW   Вверх
Alexeis
Дата 4.2.2015, 17:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



Цитата(gAlexKo @  4.2.2015,  14:19 Найти цитируемый пост)
Спасибо насчет совета о профессии. Посмотрим что вы сможете сказать по существу.

  О_о вы читаете посты снизу вверх? 

Код весьма любопытный
Код

        SF->Suspend();
        SF->Terminate();  //нить сама освободит память
        SF=NULL;

Suspend - замораживает поток, Terminate выставляет флаг потоку завершить работу, но прочитать его поток не в силах потому что спит. Имеем зависший главный поток при попытке уничтожить дополнительный (вероятно отлипает по таймауту). 

Что на счет кода
Код

blf->MeS->Lines->Add(_mess_to_MeS);

Не исключаю, что тут задействованы сообщения.  У класса 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 вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
Alexeis
Дата 4.2.2015, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



Хотя на счет SF=NULL; я, наверное, неправ. Скорее всего SF не является умным указателем, поэтому дополнительный поток просто зависнет не завершившись, а главный поток проскочит это место. Чтобы код худо бедно заработал достаточно просто убрать SF->Suspend();


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
gAlexKo
Дата 5.2.2015, 08:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Alexeis @ 4.2.2015,  17:11)
Код

        SF->Suspend();
        SF->Terminate();  //нить сама освободит память
        SF=NULL;

Suspend - замораживает поток, Terminate выставляет флаг 

Что на счет кода
Код

blf->MeS->Lines->Add(_mess_to_MeS);

Не исключаю, что тут задействованы сообщения.  У класса TMemo свой класс для Lines называется TMemoLines. Точную реализацию его не помню, но он является оберткой вокруг WinApi окна EDIT
Обмен с окнами типа EDIT осуществляется путем отсылки сообщений
<skipped>


Насчет Suspend() при выключении нитки вы правы - это не нужно, это остаток от одного из танцев с бубном.

Но похоже вы не поняли главную проблему. Я же говорю, что дело тут не в том как синхронизировать, а в том, что мистическим образом подключенные библиотеки dll не дают работать нитке(!). Стоит убрать библиотеки(обратите внимание, что они в сущности никак не задействованы), то нитка отлично начинает работать.

Чтобы не быть госолословным посылаю тот же проект, откуда выкинуты все линкованные библиотеки, а код нитки, ее запуска,  обращения к Synrnonize прежние.

Словом дело тут в тонкостях линковки и влияниях подключенных (и даже неиспользуемых) DLL на созданную нитку.



Это сообщение отредактировал(а) gAlexKo - 5.2.2015, 08:46

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  thread_NO_LIB_PROJECT.ZIP 498,68 Kb
PM MAIL   Вверх
Alexeis
Дата 5.2.2015, 11:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



Цитата(gAlexKo @  5.2.2015,  09:39 Найти цитируемый пост)
Но похоже вы не поняли главную проблему. Я же говорю, что дело тут не в том как синхронизировать, а в том, что мистическим образом подключенные библиотеки dll не дают работать нитке(!). Стоит убрать библиотеки(обратите внимание, что они в сущности никак не задействованы), то нитка отлично начинает работать.

  Они не задействованы только на первый взгляд. Три библиотеки написаны на C++ Builder 6й версии и 2е из них скомпилированны с пакетами. Это значит что они вполне себе инициализируются стандартными средствами VCL. 
                  __fastcall System::UnregisterModule(System::TLibModule *)
                  __fastcall System::RegisterModule(System::TLibModule *)
А значит определенные действия могут производить сами. Заводить таймеры, устанавливать калбеки и т.д.
Та, которая подозрительная, работает с потоками, или по крайней мере имеет средства защиты от многопоточного вызова.
DeleteCriticalSection
EnterCriticalSection
InterlockedExchange
EnumThreadWindows

  Это хорошо, если без Dll работает, но боюсь что решение проблемы остается тем же. Сам по себе механизм Synchronize потока является малоэффективным. Чтобы он сработал, должна сработать ветка OnIdle объекта Application. 
  Думаю ключевым является это место
Цитата(gAlexKo @  3.2.2015,  18:08 Найти цитируемый пост)
Стоит мне начать работать выводом на форму правильно через Synchonize - нитка останавливается, точнее если я двигаю по форме курсором мыши, то нитка работает, но только пока мышь двигается.

  Вероятно дело не в 100% загрузке проца, а в фризах главного потока. Симптомы такие, как-будто кто-то усыпляет главный поток приложения до тех пор пока не приходит сообщения. Такая функция есть в Windows, называется MsgWaitForMultipleObjects, но ее следов не обнаружено ни в одной Dll. Дело в том, что эта функция гробит механизм весь механизм фоновой обработки Application в том числе и Synchronize. Аналогичный эффект можно получить функцией GetMessage, или PeekMessage + Sleep, но ничего из перечисленного нет в секциях импорта dll.
  Головоломка, конечно, интересная, но я бы не терял время и сделал синхронизацию сообщениями, ведь при движении мыши все работает, значит сообщения Windows прерывают фриз. В любом случае сообщения Windows имеют выше приоритет обработки чем фоновые задачи, поэтому такой механизм синхронизации всегда будет более отзывчивым.



--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
xvr
Дата 5.2.2015, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


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

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



Цитата(gAlexKo @  5.2.2015,  08:39 Найти цитируемый пост)
Стоит убрать библиотеки(обратите внимание, что они в сущности никак не задействованы),

Кроме уже упомянутых Alexeis вызовов инициализации пакета, стоит отметить, что ваша -
Цитата(gAlexKo @  4.2.2015,  13:19 Найти цитируемый пост)
что если убрать из заголовка формы стркутуру из dll (ACP_HEAD), 
не структура, а класс с конструктором. Так что как минимум еще вызывается конструктор этого самого ACP_HEAD. Так что постулат о 'незадействованности' неверен уже дважды  smile 

PM MAIL   Вверх
gAlexKo
Дата 5.2.2015, 17:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(xvr @ 5.2.2015,  14:48)
Цитата(gAlexKo @  5.2.2015,  08:39 Найти цитируемый пост)
Стоит убрать библиотеки(обратите внимание, что они в сущности никак не задействованы),

Кроме уже упомянутых Alexeis вызовов инициализации пакета, стоит отметить, что ваша -
Цитата(gAlexKo @  4.2.2015,  13:19 Найти цитируемый пост)
что если убрать из заголовка формы стркутуру из dll (ACP_HEAD), 
не структура, а класс с конструктором. Так что как минимум еще вызывается конструктор этого самого ACP_HEAD. Так что постулат о 'незадействованности' неверен уже дважды  smile

Так как это моё, то могут сказать, что в конструкторе ACP_HEAD делается только очистка памяти структуры.  Переменные в структуре выделяются без всяких new (это тянется с тех времен когда это было на Си).

Добавлено @ 17:34
Цитата(Alexeis @ 5.2.2015,  11:36)
  Головоломка, конечно, интересная, но я бы не терял время и сделал синхронизацию сообщениями, ведь при движении мыши все работает, значит сообщения Windows прерывают фриз. В любом 

Я решил попробовать использовать критическую секцию TCriticalSection и мне очень понравилось. Типа идея простая - на период вывода нить блокирует все другие нити, в том числе и VCL. Я сделал новый короткий образец (см в архиве).

Единственная засада которую я не смог приодолеть. ;-) Если я (после запуска нити) выключаю нитку кнопкой, а затем закрываю форму выходя из программы все работает.

Если я закрываю форму с работаюшей нитью (крестом формы), то вылетает ошибка. Как я не трахался, но я не смог найти как закрыть форму с работающей ниткой. Что я делаю не так в CloseForm? Задача вроде тривиальная, но... не выходит.

Это сообщение отредактировал(а) gAlexKo - 5.2.2015, 17:37

Присоединённый файл ( Кол-во скачиваний: 2 )
Присоединённый файл  Krit_sec.zip 6,69 Kb
PM MAIL   Вверх
Alexeis
Дата 5.2.2015, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Амеба
Group Icon


Профиль
Группа: Админ
Сообщений: 11743
Регистрация: 12.10.2005
Где: Зеленоград

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



Цитата(gAlexKo @  5.2.2015,  18:21 Найти цитируемый пост)
Я решил попробовать использовать критическую секцию TCriticalSection и мне очень понравилось. Типа идея простая - на период вывода нить блокирует все другие нити, в том числе и VCL. Я сделал новый короткий образец (см в архиве).

  Критическая секция сама по себе не поможет. Программист не знает всех мест где VCL обращается к Memo, поэтому невозможно изолировать эти операции от своего кода. Можно только в сообщении, поскольку мы точно знаем, что VCL поток занят обработкой сообщений и он точно ничего не делает в данный момент.

Цитата(gAlexKo @  5.2.2015,  18:21 Найти цитируемый пост)
Единственная засада которую я не смог приодолеть. ;-) Если я (после запуска нити) выключаю нитку кнопкой, а затем закрываю форму выходя из программы все работает.

Это от того что используется упрощенный способ завершения потока. Нужно убрать автоудаление потока и при завершении программы сначала вызвать Terminate, затем WaitFor, а потом уже можно смело делать ему delete 


--------------------
Vit вечная память.

Обсуждение действий администрации форума производятся только в этом форуме

гениальность идеи состоит в том, что ее невозможно придумать
PM ICQ Skype   Вверх
gAlexKo
Дата 6.2.2015, 08:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


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

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



Цитата(Alexeis @ 5.2.2015,  18:30)
Цитата(gAlexKo @  5.2.2015,  18:21 Найти цитируемый пост)
Я решил попробовать использовать критическую секцию TCriticalSection и мне очень понравилось. Типа идея простая - на период вывода нить блокирует все другие нити, в том числе и VCL. 

  Критическая секция сама по себе не поможет. Программист не знает всех мест где VCL обращается к Memo, поэтому невозможно изолировать эти операции от своего кода. Можно только в сообщении, поскольку мы точно знаем, что VCL поток занят обработкой сообщений и он точно ничего не делает в данный момент.

Но ведь смысл использования 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 -----

Таким образом
Код

           blf->CSec->Acquire();
           try
           {
              blf->MeS->Lines->Add(mess);
           }

           __finally
           {
           blf->CSec->Release();
           }



не должен быть в конфликте с VCL?

Это сообщение отредактировал(а) gAlexKo - 6.2.2015, 08:28
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

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

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

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

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


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

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


 




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


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

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