| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Delphi: Общие вопросы > Почему зависает поток? |
| Автор: UKRtortik 24.3.2014, 08:15 | ||
Почему при старте зависает поток?
|
| Автор: Poseidon 26.3.2014, 07:49 |
| Откуда сведения о том, что зависает? Долго HTTPSend.HTTPMethod('GET', Site); обрабатывается? Так это нормально. |
| Автор: UKRtortik 14.4.2014, 14:09 |
| Poseidon, при старте программа полностю зависает секунд на 5-10, из-за чего? |
| Автор: CynicRus 14.4.2014, 14:58 |
| Application.ProcessMessage попробуй. Из-за чего? Может из-за цикла, может из-за Get. |
| Автор: UKRtortik 14.4.2014, 15:02 |
| А где именно должен быть Application.ProcessMessages? |
| Автор: UKRtortik 14.4.2014, 15:18 | ||
Не помогает. |
| Автор: Romikgy 14.4.2014, 15:22 |
| в потоке имхо надо... |
| Автор: UKRtortik 14.4.2014, 15:24 |
| а где именно в потоке? |
| Автор: Poseidon 14.4.2014, 15:34 |
| Тут нужно смотреть код. Может в OnCreate что-то "тяжелое" выполняется, может еще что. Так просто "на глаз" сказать сложно. |
| Автор: UKRtortik 14.4.2014, 15:52 |
| при чем сдесь OnCreate? Они же не при запуске программы зависает. А когда поток запускаю. |
| Автор: Romikgy 14.4.2014, 15:57 |
| где то между repeat & until (если не http затыка) |
| Автор: UKRtortik 14.4.2014, 16:31 |
| не помогает |
| Автор: UKRtortik 14.4.2014, 17:03 | ||
А как с этим бороться? |
| Автор: Romikgy 14.4.2014, 17:07 |
| интернет мощнее |
| Автор: PointerToNil 14.4.2014, 17:23 |
| я бы первым делом избавился от synchronize совсем (есть postmessage, events и можно общаться просто через переменные/поля) synchronize - главный источник проблем начинающих многопоточников |
| Автор: UKRtortik 14.4.2014, 17:38 |
| А как без синхронизации сделать, я не много не понял. |
| Автор: PointerToNil 14.4.2014, 17:52 |
| я же ключевые слова давал или хотя бы так: http://codeguide.ru/peredacha-informatsii-iz-potoka-delphi.html (только postmessage вместо sendmessage) |
| Автор: Poseidon 14.4.2014, 19:05 |
| С Synchronize запись в Memo делается двумя строчками кода. Извращаться для данной задачи с помощью PostMessage - это как в Питер из Москвы через Владивосток. Можно, но не целесообразно. При любом раскладе, даже с помощью PostMessage, мы передаем управление в VCL-поток для отрисовки Memo. Так почему же не воспользоваться специально предназначенным для этого Synchronize? Ну а общение через переменные - это вообще аут. А как эти переменные в VCL-потоке считывать? Цикл крутить? Таймер задействовать? Synchronize тут правильно использовано. |
| Автор: UKRtortik 14.4.2014, 20:39 |
| ну так как мне правильно сделать? В чем у меня ошибка? |
| Автор: Romikgy 14.4.2014, 20:55 |
| сначала надо определится в каком месте виснет |
| Автор: CynicRus 14.4.2014, 21:01 |
| В 17-ой строке у тебя ошибка. А если серьёзно - загружаешь свой проект, и пошагово смотришь по нажатию F8, где же он тормозит. Предварительно расставив бряки. |
| Автор: UKRtortik 14.4.2014, 21:12 |
| а что не так в 17 строке? |
| Автор: CynicRus 14.4.2014, 21:15 | ||
Это древняя шутка про отсутствие телепатических способностей. К делу отношения не имеет. Просто посмотри под отладчиком. |
| Автор: UKRtortik 14.4.2014, 21:33 | ||
| просто не очень понимаю как пользоватся отладчиком.... Добавлено через 1 минуту и 50 секунд
|
| Автор: PointerToNil 14.4.2014, 21:44 |
| UKRtortik, проверил свою ссылку - не работает, весь сайт накрылся - а вы что молчите?? вот, держите копию: http://webcache.googleusercontent.com/search?q=cache:JIN129MuqNwJ:codeguide.ru/peredacha-informatsii-iz-potoka-delphi.html а для начала я бы тупо закомментировал строку с synchronize и посмотрел бы на быстродействие Рoseidon> С Synchronize запись в Memo делается двумя строчками кода. точно. на этом все и ловятся Рoseidon> При любом раскладе, даже с помощью PostMessage, мы передаем управление в VCL-поток для отрисовки Memo. НЕТ же! асинхронное сообщение передаёт данные, а не управление. как и переменные. передать управление из потока в поток вообще невозможно, хотя можно организовать видимость этого, тупо приостановив "вызывающий" поток до завершения действия в "вызываемом", что и делает synchronize Рoseidon> Ну а общение через переменные - это вообще аут. А как эти переменные в VCL-потоке считывать? Цикл крутить? не "аут", а банальное низкоуровневое решение вы наверное удивитесь, но окно принимает/обрабатывает сообщения тоже крутя цикл согласен, что подобный низкоуровневый код лучше куда-то заинкапсулировать, но раз борланд не справился... можно юзать OmniThreadLibrary или AsyncCalls еще Рoseidon> таймер использовать? проще sleep, хотя я бы предпочел CreateEvent и WaitForSingleObject так уж вышло, что "из коробки" synchronize оказался единственным удобным средством для передачи сообщений VCL-потоку но эта штука специфичная. гораздо полезнее во многих случаях был бы "Asynchronize" - то есть то же самое, но без приостановки потока (т. е. без удара по быстродействию) вот тут недавно чел пострадал от synchronize: http://forum.vingrad.ru/index.php?showtopic=376703&view=findpost&p=2604306 |
| Автор: Poseidon 14.4.2014, 22:41 | ||||
http://forum.vingrad.ru/act-Help/CODE-01/HID-17.html
По твоему подобные решения лучше Synchronize? Может вообще тогда на ассамблере писать, чо уж там? |
| Автор: PointerToNil 14.4.2014, 23:03 |
| Poseidon> По твоему подобные решения лучше Synchronize? возможно, лучшее решение - Asynchronize, но его пока нет (и мне не нужно, а то мог бы попробовать набросать) врожденный порок (для кого-то - фича) synchronize никуда не денется: он тупо останавливает вызывающий поток! кому это нужно? мне нет, поэтому любое решение, этого не делающее - для меня лучше Poseidon> Может вообще тогда на ассамблере писать, чо уж там? если речь о функции-утилите, которая пишется 1 раз, а используется в тысяче мест - то многие так и делают (в применении к потокам - смысла в ассемблере нет) |
| Автор: Poseidon 15.4.2014, 01:13 |
| Это дает гарантию, что к общему ресурсу (в частности к VCL-объекту) имеет доступ только один поток. Видимо PointerToNil не сталкивался с ситуациями, когда пока один поток перепрыгнет на одну строку, второй поток уже считает данные и изменит их. Synchronize для того и задуман, что бы гарантировать доступ только одного потока. Если у нас ситуация, когда один поток должен работать с данными, которые высчитываются в другом потоке, то как можно гарантировать правильность расчетов? |
| Автор: PointerToNil 15.4.2014, 02:16 |
| Poseidon, у меня просто слов нет, чтобы выразить... конечно, к VCL-объекту имеет доступ только один поток - поток VCL!!! не в вызывающем же потоке исполняется метод-параметр synchronize! если возникли сомнения: http://forum.vingrad.ru/index.php?showtopic=60076&view=findpost&p=480368 и подробнее: http://www.delphiplus.org/articles/delphi/multi-threads_programs.html вот только зачем вызывающий поток-то для этого останавливать? это даже гарантию немедленного исполнения требуемого действия не может дать - поток VCL чем-то своим еще может быть занят хотя на однопроцессорных и однотредовых машинах эта остановка еще имела смысл (ускорить запуск требуемого метода), но на многопроцессорных смысла уже не осталось очевидно, это - реликт, оставшийся от старой эпохи (хотя скорее всего могли и тогда более правильно это сделать) а вот и возможное решение (из второй ссылки): По сравнению с Delphi 7 в классы потоков Delphi 2009 внесено много изменений. Прежде всего, в класс TThread добавлена группа перегруженных методов Queue, которые позволяют синхронизировать вызов методов с главным потоком в неблокирующем режиме. Poseidon> Видимо PointerToNil не сталкивался с ситуациями, когда пока один поток перепрыгнет на одну строку, второй поток уже считает данные и изменит их конечно нет, как же это, совсем без критических секций что ли?? (а для простых типов данных, <=4 байта - есть interlocked* функции) Poseidon>Если у нас ситуация, когда один поток должен работать с данными, которые высчитываются в другом потоке, то как можно гарантировать правильность расчетов? ну как бы сразу напрашивается переменные/поля на 3 состояния, сигнализирующие о том, что обработка данной порции данных еще не начата/начата/уже закончена или 2 переменные - счетчики числа взятых на обработку элементов и числа уже обработанных (причем синхронизировать доступ к ним (interlocked*) нужно только для операции установки состояния "взято на обработку" или увеличения счетчика взятых на обработку, только между несколькими потоками-обработчиками и только в случае, если их несколько, а VCL-поток волен читать их в любой момент) - но для кого-то это может показаться слишком простым и низкоуровневым, [sarcasm] тут же без пары крутых специальных классов с дюжиной методов не обойтись [/sarcasm] не любите циклы с ожиданием? используйте CreateEvent, (Re)SetEvent и WaitFor(Single|Multiple)Object |
| Автор: Poseidon 15.4.2014, 09:03 | ||||||
Это не решение, а один из вариантов. Если потоку надо "вбросить" данные в VCL и идти дальше (как в случае автора), то Queue подойдет. А если потоку надо работать с данными VCL, то тут нужна гарантия что кто-то другой (поток или даже сам пользователь) не поменял эти данные в процессе. А теперь самое интересное. У UKRtortik в Synchronize одна строчка кода, которая обрабатывается за долю секунды. Неужели блокировка потока на эту долю секунды и есть то самое "зависание" о котором пишет UKRtortik? Неужели если мы отправим в VCL неблокирующее сообщение вместо Synchronize, то поток не "зависнет"? Там по коду отчетливо видно, что поток посылает Get в сеть и ждет ответ. Вот это ожидание и есть причина. А Synchronize там вообще не при чем. Модератор: Давайте вернёмся к теме обсуждения. |
| Автор: Romikgy 15.4.2014, 09:19 |
| F7 & F8 |
| Автор: PointerToNil 15.4.2014, 10:39 | ||
| Poseidon> А если ситуация, когда потоку надо обратиться к VCL несколько раз подряд? Как без блокируещего метода и без бубна гарантировать, что предыдущее обращание завершилось? это гарантируется тупо тем, что поток VCL только один и, естественно, обращения к нему выстраиваются в очередь (ну загляни в classes.pas что ли уже, если ссылки tl;dr) Poseidon> Т.е. если один поток отрабатывает критическую секцию, второй поток не ждет на входе в нее? Второй поток не простаивает? Это чем-то принципиально отличается от Synchronize? да. отличается по области применения. критические секции (или атомарный доступ к предложенным мной переменным-признакам или счетчикам) нужны для сериализации (очередизации) доступа к данным среди потоков-копий из одной группы/пула - они могут за эти данные конкурировать, например, пытаться одновременно "забрать" себе на обработку один очередной необработанный блок. а в ситуации как у ТС, когда "рабочий" поток уже обработал блок данных и он ему больше не нужен, поток следующего этапа (занимающийся выводом) может его спокойно (если этот поток в одном экземпляре) забирать, он должен только о его готовности узнать либо по переменной-признаку, либо по сообщению в своей очереди. без конкуренции потоков синхронизация гораздо проще (нет толкотни соседей по очереди) Poseidon> Ну да, реально проще наворотить с три короба кода, придумать крутые алгоритмы с переменными, сигнализированием, счетчиками да никаких "алгоритмов" тут нет! самое сложное тут - это
(обычно это успевают сделать за нас еще в Микрософте/Борлакадеро, и там у них внутри те же примитивные переменные и циклы) Poseidon> А в чем разница, или поток будет крутить в холостую цикл, ожидая когда же нужная переменная примет нужное значение, что бы пойти дальше, или поток остановится, ожидая Synchronize? предполагается, что "крутить цикл" будет ожидающий данных (пока еще не готовых) поток второго этапа (вывода и т.п.), а останавливать по Synchronize я не хочу потоки первого этапа ("рабочие"), к которым навалом других сырых данных в очереди ещё стоит (если вдруг наоборот, в очереди на вывод скопление образуется, то и крутить вхолостую ничего не придется) Poseidon>А если потоку надо работать с данными VCL, то тут нужна гарантия... да что же это такое то?!?! с данными VCL номинально разрешено работать только потоку VCL. к счастью, он у нас только один гарантий же от глупости программиста никакие волшебные классы/методы/функции никогда не дадут в частности, Synchronize блокирует только свой собственный поток (думаете, авторы VCL предполагали, что программист, только что послушно выполнив их рекомендации и вызвав правильный метод, может ТУТ ЖЕ СРАЗУ уйти в отрыв и с горя полезть в VCL напрямую, поэтому и решили это дело заблокировать?!? сорри за эмоции, если что) при этом Synchronize ничуть НЕ блокирует ВСЕ остальные потоки (вообще по-хорошему только сам поток может себя "поставить на паузу", как и закончить, хотя через winapi... но это не рекомендуется) Модератор: Давайте вернёмся к теме обсуждения. а без тредстартера основная тема все равно пока WaitingForSingleObject |
| Автор: Poseidon 15.4.2014, 12:58 | ||||||||
"Это" - 10 строк кода в примитивной реализации. Synchronize займет одну.
PointerToNil, если есть желание обсудить никчемность Synchronize, можешь создать для этого отдельную тему. |
| Автор: UKRtortik 15.4.2014, 15:33 | ||
Извините я возможно не заметил, ну где мне указали причину? |
| Автор: Poseidon 15.4.2014, 15:36 | ||
|
| Автор: UKRtortik 15.4.2014, 15:38 |
| а что с этим делать? |
| Автор: stanilar 15.4.2014, 17:19 |
| Tесли HTTPSend - это Indy, то у ней может быть свой механизм потоков, с странным поведением которого вы и сталкиваетесь. |
| Автор: Poseidon 15.4.2014, 17:36 |
| Автор: UKRtortik 15.4.2014, 21:14 |
![]() этого что недостаточно? |
| Автор: Poseidon 15.4.2014, 22:13 |
| А покажи пинг того ресурса, куда отправляется Get. |
| Автор: PointerToNil 16.4.2014, 08:39 |
| Poseidon, я все же сделаю еще одну попытку объяснить недопонятое, потому, что иначе затраченные нами обоими на этот разговор усилия оказываются совсем бесполезными. А так остаётся маленькая надежда. Те приведенные 10 строк - вовсе не замена synchronize, они нужны для совсем другого случая - а именно, для сериализации доступа к данным между конкурирующими за них потоками (перечитайте абзац, где упоминается конкуренция). Там synchronize не применим никак, так как разбираться друг с другом должны несколько рабочих (неглавных) потоков! (обычно их число = числу ядер или *2 для гипертрединговой архитектуры). Участвует ли в этой конкуренции еще и главный (VCL) поток или нет - значения не имеет. Interlocked* функции (пример в тех 10 строках) - облегченная замена критическим секциям для случаев, когда нужна одноразовая атомарная операция с переменной/полем простого типа. А вот TThread.Queue - отличный вариант (как замена synchronize), я как раз за него! (если он есть в вашей версии дельфей) "без тредстартера основная тема все равно пока WaitingForSingleObject" - перевожу на русский: без тредстартера основная тема все равно пока зависла в ожидании одного объекта, т.е. тредстартера (это была попытка пошутить) BTW, собрал и запустил код тредстартера - никакие "подвисания" не проявились |
| Автор: CynicRus 16.4.2014, 09:49 | ||||
Яж тебе говорил - под отладчиком пошагово посмотри, где у тебя тормозит. Как пользоваться отладчиком? http://habrahabr.ru/post/178007/ |
| Автор: UKRtortik 16.4.2014, 15:53 | ||
а как понять из-за чего зависает в открадчике? Зависать начинает на этой строке:
|
| Автор: PointerToNil 16.4.2014, 18:36 |
| UKRtortik, тебе нужно найти строку в коде программы, исполнение которой тормозит 1 поставь breakpoint (F5) на первой после begin строке TNewThread.Execute 2 запусти программу (F9), в ней - свой тред, дождись срабатывания брейкпоинта (открытия экрана дельфи) 3 теперь жми F8 и следи за задержкой (между скрытием и новым появлением экрана дельфей, обычно это мерцание даже не успеваешь заметить) - многократно, пока не найдешь (или до выхода из метода) |
| Автор: UKRtortik 23.4.2014, 11:37 |
| PointerToNil, что-то я соровно так и не смог разобратся.... |