|
|
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
При закрытии приложения из-за несинхронного закрытия потоков событие лога возникает в тот момент, когда форма уже удалена, и переменная memo содержит nil, что приводит к ошибке. Нельзя закрывать главное окно приложения, пока есть дополнительные потоки. Варианты могут быть например такие: а) при закрытии главного окна вызывать Free объекту потока (при этом у потока свойство FreeOnTerminate должно быть False), также нежелательно в таком потоке иметь вызовы Syncronize, т.к. может возникнуть взаимная блокировка доп. потока на этом вызове и главного потока на вызове Free. б) если поток создаётся на короткое время, а потом уничтожается и у него FreeOnTerminate=True, то при закрытии главного окна можно проверять, работает (создан) ли этот поток и на событие OnCloseQuery выдавать на экран MessageBox, мол "у Вас запущен поток попытайтесь закрыть программу чуть позже" (и выставлять CanClose=False). в) если поток создаётся на короткое время, а потом уничтожается и у него FreeOnTerminate=True, то при закрытии главного окна в событии OnCloseQuery можно всем запущенным потокам сообщать о необходимости закрытия (выставить глобальную переменную, которую постоянно мониторят все доп. потоки, у которых выставлен FreeOnTerminate=True). Далее вывести на экран сообщение "Вы действительно хотите закрыть программу?". Пока пользователь это сообщение нажимает, потоки успеют закрыться. Но здесь головой думать надо, не факт, что это идеальный вариант. Пользователь может и отказаться закрывать программу, тогда у программы не будет доп. потоков, о чём пользователь также желательно будет сообщить :) Уверен, что у каждого здесь свой рецепт, как правильно завершить программу при наличии доп. потоков! Кто поделится своими рецептами? :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.02.2020, 09:12 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
Вспомнил ещё один вариант, который часто использую: 1) создаёт поток (с FreeOnTerminate=True) и сохраняем ссылку на него в глобальной переменной MyThread 2) в Execute потока мониторим глобальную переменную Stop (если она = True, то делаем Exit) 3) у потока реализуем перегруженный деструктор и в нем после inherited делаем MyThread := nil 4) при закрытии главной формы выставляем Stop=True, далее в цикле проверяем значение в переменной MyThread, допустим 100 итераций по 10 мс (должно хватить). Если переменная MyThread всё ещё имеет значение, то перестаём ожидать поток, но выводим в лог сообщение. Также поступаем со всеми остальными аналогичными потоками. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.02.2020, 09:26 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
а) при закрытии главного окна вызывать Free объекту потока (при этом у потока свойство FreeOnTerminate должно быть False), также нежелательно в таком потоке иметь вызовы Syncronize, т.к. может возникнуть взаимная блокировка доп. потока на этом вызове и главного потока на вызове Free. Судя по коду метода WaitFor, такая блокировка обрабатывается и успешно разруливается. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.02.2020, 12:27 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
VirtaOtec Или это неправильный подход? Это крайне сомнительный и хрупкий подход, который вызывает кучу вопросов, в частности, как вообще организована запись в memo и почему поток не может проверить флаг типа "идёт выход из приложения, все заткнитесь и умрите". ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.02.2020, 12:47 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer как правильно завершить программу при наличии доп. потоков! Кто поделится своими рецептами? :) Вот единственный нормальный вариант: DmSer а) при закрытии главного окна вызывать Free объекту потока (при этом у потока свойство FreeOnTerminate должно быть False), также нежелательно в таком потоке иметь вызовы Syncronize, т.к. может возникнуть взаимная блокировка доп. потока на этом вызове и главного потока на вызове Free Если потоков несколько, разных, но которые зависят друг от друга (один управляет другим) - то при таком подходе легко можно остановить их в нужном порядке. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.02.2020, 01:37 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer а) при закрытии главного окна вызывать Free объекту потока (при этом у потока свойство FreeOnTerminate должно быть False), также нежелательно в таком потоке иметь вызовы Syncronize, т.к. может возникнуть взаимная блокировка доп. потока на этом вызове и главного потока на вызове Free. Судя по коду метода WaitFor, такая блокировка обрабатывается и успешно разруливается. Это не так. Метод, добавленный в список Synchronize, может еще не начать выполняться, а WaitFor уже вызван (при обработке главным потоком сообщения, которое обрабатывалось в момент этого добавления) - и тогда грабли выстрелят. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.02.2020, 01:44 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
YuRock DmSer пропущено... Судя по коду метода WaitFor, такая блокировка обрабатывается и успешно разруливается. Я не смог воспроизвести такую проблему. Специально разработал тестовое приложение, в котором создавался доп. поток, в нём в цикле вызывался Synchronize / SendMessage (с паузой Sleep(0)), а в главном потоке таймер, который срабатывал раз в 5 мс и создавал поток либо делал ему Free. Никаких блокировок не было. Проверял на версии 10.3.3. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 23.02.2020, 09:01 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
YuRock, WaitFor насколько я помню обязан дождаться начало и конец всех Synchronize перед выходом из него. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.02.2020, 13:15 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
makhaon YuRock, WaitFor насколько я помню обязан дождаться начало и конец всех Synchronize перед выходом из него. Вопрос, что будет, если waitfor уже вызван в оконном потоке, а еще не все synchronize-вызовы обработалист в execute. Ответ - будет дедлок. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 24.02.2020, 21:00 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer Вспомнил ещё один вариант, который часто использую: 1) создаёт поток (с FreeOnTerminate=True) и сохраняем ссылку на него в глобальной переменной MyThread 2) в Execute потока мониторим глобальную переменную Stop (если она = True, то делаем Exit) 3) у потока реализуем перегруженный деструктор и в нем после inherited делаем MyThread := nil 4) при закрытии главной формы выставляем Stop=True, далее в цикле проверяем значение в переменной MyThread, допустим 100 итераций по 10 мс (должно хватить). Если переменная MyThread всё ещё имеет значение, то перестаём ожидать поток, но выводим в лог сообщение. Также поступаем со всеми остальными аналогичными потоками. Очень много совершенно лишних сущностей. Если ссылка и так есть в глоб. переменной, то вместо Stop прекрасно подойдет Terminated потока, да и обнулять ссылку на себя не нужно. И раз уж код закрытия и так ожидает, определять, что Execute завершилась, можно по ExitCode. В общем, Terminate + WaitFor самое корректное. Если же поток может отправлять сообщения, то стоит после WaitFor запустить ProcessMessages (а для более чистой обработки лучше даже собственную выборку GetMessage, вычерпывающую только сообщения от потоков). Правда, обработчик при этом должен понимать, что программа завершается, и не делать ничего противоречащего (запуск новых потоков и т.п.) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.02.2020, 10:16 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
YuRock makhaon YuRock, WaitFor насколько я помню обязан дождаться начало и конец всех Synchronize перед выходом из него. Вопрос, что будет, если waitfor уже вызван в оконном потоке, а еще не все synchronize-вызовы обработалист в execute. Ответ - будет дедлок. она обрабатывает появившиеся synchronize и сообщения ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.02.2020, 11:24 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
Василий 2 DmSer Вспомнил ещё один вариант, который часто использую: 1) создаёт поток (с FreeOnTerminate=True) и сохраняем ссылку на него в глобальной переменной MyThread 2) в Execute потока мониторим глобальную переменную Stop (если она = True, то делаем Exit) 3) у потока реализуем перегруженный деструктор и в нем после inherited делаем MyThread := nil 4) при закрытии главной формы выставляем Stop=True, далее в цикле проверяем значение в переменной MyThread, допустим 100 итераций по 10 мс (должно хватить). Если переменная MyThread всё ещё имеет значение, то перестаём ожидать поток, но выводим в лог сообщение. Также поступаем со всеми остальными аналогичными потоками. Очень много совершенно лишних сущностей. Если ссылка и так есть в глоб. переменной, то вместо Stop прекрасно подойдет Terminated потока, да и обнулять ссылку на себя не нужно. И раз уж код закрытия и так ожидает, определять, что Execute завершилась, можно по ExitCode. В общем, Terminate + WaitFor самое корректное. Если же поток может отправлять сообщения, то стоит после WaitFor запустить ProcessMessages (а для более чистой обработки лучше даже собственную выборку GetMessage, вычерпывающую только сообщения от потоков). Правда, обработчик при этом должен понимать, что программа завершается, и не делать ничего противоречащего (запуск новых потоков и т.п.) Всё это хорошо при условии FreeOnTerminate=False. Ежели FreeOnTerminate=True, то обращения к доп. потоку с помощью переменной (MyThread) потенциально опасны, т.к. объект потока может исчезнуть в любой момент, никакой ExitCode в этом случае не спасёт. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.02.2020, 13:00 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
Если же поток может отправлять сообщения, то стоит после WaitFor запустить ProcessMessages (а для более чистой обработки лучше даже собственную выборку GetMessage, вычерпывающую только сообщения от потоков). Правда, обработчик при этом должен понимать, что программа завершается, и не делать ничего противоречащего (запуск новых потоков и т.п.) Стараюсь не использовать метод Application.ProcessMessages, т.к. из-за него слишком уж много граблей. Всегда можно обойтись другими средствами. А для чего делать выборку сообщений? Что, разве при вызове WaitFor сообщения могут пропасть? Кстати, а по какой причине при вызове WaitFor из основного потока не блокируются вызовы SendMessage из доп. потока? Из-за PeekMessage с параметром PM_NOREMOVE? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.02.2020, 13:13 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer Всё это хорошо при условии FreeOnTerminate=False. Ежели FreeOnTerminate=True, то обращения к доп. потоку с помощью переменной (MyThread) потенциально опасны, т.к. объект потока может исчезнуть в любой момент, никакой ExitCode в этом случае не спасёт. А FreeOnTerminate=True в принципе вредная конструкция. Если она применяется, то о корректном завершении в случае принудительного закрытия приложения не может быть речи (либо же, так или иначе, вводить некий глобальный флаг, что тоже не очень хорошо). DmSer Стараюсь не использовать метод Application.ProcessMessages, т.к. из-за него слишком уж много граблей. Всегда можно обойтись другими средствами. Грабли в самом деле могут быть, если их специально не прикрыть заранее. А для чего делать выборку сообщений? Что, разве при вызове WaitFor сообщения могут пропасть? Если потоки завершаются из Form.OnDestroy, то конечно пропадут. Из Form.OnClose не должны ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 25.02.2020, 15:03 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer из-за него слишком уж много граблей Я список этих граблей давно с фонарем ищу. Можешь перечислить? :) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.02.2020, 18:47 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
Док Я список этих граблей давно с фонарем ищу. Можешь перечислить? :) Повторный запуск не рассчитанных на это процедур, если они запускаются по событию от юзера. В нашем случае - повторное закрытие, например. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.02.2020, 19:17 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
Василий 2 Повторный запуск не рассчитанных на это процедур, если они запускаются по событию от юзера. Для отсутствия таких проблем стоит пользоваться action-ами (особенно - правильно доработанными action-ами). Осталось засунуть ещё буквально в пару мест, типа того же CloseQuery, соответствующую проверку - и вуаля. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 26.02.2020, 19:22 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
softwarer Для отсутствия таких проблем стоит пользоваться action-ами (особенно - правильно доработанными action-ами). Осталось засунуть ещё буквально в пару мест, типа того же CloseQuery, соответствующую проверку - и вуаля. C ними не очень знаком, всегда воспринимал их как просто контейнер для обработчиков, ну и способ привязать несколько источников к одному обработчику. Как они помогут избежать нежелательного повторного вызова? Разве что дизейблить экшен внутри обработчика... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 10:35 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
softwarer > особенно - правильно доработанными action-ами А что конкретно ты там патчил? Posted via ActualForum NNTP Server 1.5 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 10:54 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
Василий 2 всегда воспринимал их как просто контейнер для обработчиков ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 12:26 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
Док DmSer из-за него слишком уж много граблей Я список этих граблей давно с фонарем ищу. Можешь перечислить? :) Одна из недавно обнаруженных проблем, которая возникает из-за Application.ProcessMessages: используем технологию DataSnap, компонент TSocketConnection. Оказалось, что если DCOM-сервер находится не в локальной сети, а через интернет, то Application.ProcessMessages входит в бесконечный цикл и не возвращает управление. Вот процедура WaitCmd, в которой бесконечно выполняется Application.ProcessMessages: Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. Поток FThread отвечает за формирование отчёта (через отдельное подключение TSocketConnection, которое создаётся в потоке). Поток тупо вызывает функцию AppServer.CreateReport(...) у TSocketConnection и выставляет флаг IsReady и запоминает результат (отчёт). На форме WaitForm таймер, который несколько раз в секунду обращается к DCOM-серверу через подключение TSocketConnection, созданное в главном потоке и двигает ProgressBar. Для формирования отчёта главный поток вызывает функцию GetReport: Код: pascal 1. 2. 3. 4. 5. 6. 7. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 12:55 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer компонент TSocketConnection ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 13:37 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
vavan DmSer компонент TSocketConnection Мы очень много времени потратили на исправление различных багов в модуле SConnect.pas. Но в итоге мы своего добились - оно заработало. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 13:44 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer Мы очень много времени потратили на исправление различных багов в модуле SConnect.pas ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 14:00 |
|
||
|
waitFor в потоке
|
|||
|---|---|---|---|
|
#18+
DmSer Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. А не легче WaitForm.ShowModal, а по таймеру if FThread.IsReady then ModalResult := mrOK? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 27.02.2020, 14:12 |
|
||
|
|

start [/forum/topic.php?fid=58&msg=39931698&tid=2038538]: |
0ms |
get settings: |
9ms |
get forum list: |
20ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
57ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
86ms |
get tp. blocked users: |
1ms |
| others: | 225ms |
| total: | 421ms |

| 0 / 0 |
