|
|
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Добрый день! Прочитал много всего про потоки, в том числе и на этом форуме. Но не могу понять как правильно реализовать мою задачу. Максимально упрощенная задача: Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude. Как я пытаюсь сделать: Есть форма с TGaude на нем. Есть поток: Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. Я создаю поток suspended = true, после создания присваиваю его публичному свойству FMyForm ссылку на только что созданную форму, и запускаю на выполнение: Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. В самой форме описана процедура изменения ползунка. И этот метод я вызываю в цикле Execute потока. Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. Этот метод не знает что он вызван в Execute потока. Я не понимаю как нужно сделать возможность безопасного закрытия формы пользователем в момент выполнения потока. Когда я просто закрываю форму - поток остается работать, и пытается что то менять на уже уничтоженной форме. (Форма уничтожается в момент закрытия). Т.е. конечно же нужно перед закрытием формы уничтожить поток, который на этой форме что то делает. Следовательно - форма должна знать о потоке. Следовательно - после создания потока я указываю его как значение поля формы FMyThread: Код: pascal 1. И в onclose формы делать так: Код: pascal 1. 2. 3. Но эксперименты показывают что это все неправильно, ибо вылазит ошибка на WaitFor : "Неверный дескриптор" Ну и то что поток вызывает метод формы, который описан в самой форме, и который не знает что его вызвал поток - это кмк тоже неправильно. Какая должна быть правильная архитектура такой задачи? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 18:37 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Может генерировать события? Пользователь вызывает событие closeQuery у формы. В closeQuery мы пишем потоку terminate. И после создания потока мы подписываемся на событие onTerminate потока. И после возникновения события устанавливаем переменную FCanClose в true Как то так что ли... ... Короче - каша в голове. Не хватает опыта работы с потоками... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 18:45 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Нашел ошибку: после уничтожения потока нужно полю формы FThread (то которое ссылается на управляющий поток) присваивать nil. ... Но все равно - архитектура какая то люто неправильная... Все на все ссылается.... Никакой абстракции... .. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 20:10 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Пришел к тому, что действия которые что то делают с формой, должны быть описаны в классе потока. Также как и какие то длительные действия - паузы, ожидания чего-либо. Ибо в классе самого потока я смогу анализировать поле terminated экземпляра потока, и вовремя прекращать. Т.е. создаем форму. Создаем поток. Полю FMyForm потока присваиваем myForm И наоборот: полю FMyThread формы присваиваем ссылку на поток. Когда пользователь закрывает форму руками, мы сначала уничтожаем поток, и ждем его завершения. Чтобы это было максимально быстро - во всех действиях ожиданиях и паузах, описанных в потоке анализируем terminated. Ну и после уничтожения потока полю формы FmyThread присваиваем nil. Не красиво, но работать будет. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 20:28 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
BasketbolПрочитал много всего про потоки, в том числе и на этом форуме. Вы, судя по всему, даже комментарий, который среда создаёт для нового потока, не прочитали. Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 21:04 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Basketbol, Не говоря уже о том, что вы вообще не понимаете что вы делаете: Код: pascal 1. 2. 3. 4. 5. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 21:06 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
может применить компоненту, которая инкапсулирует всю работу с потоком внутри? их есть несколько разных. то, что сейчас сделано, конечно, можно в сотый раз поругать, но не знаю надо ли ) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 21:19 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
alekcvpBasketbol, Не говоря уже о том, что вы вообще не понимаете что вы делаете: Код: pascal 1. 2. 3. 4. 5. Не говоря о том, что Terminate и WaitFor будут вызваны в деструкторе (если он вызовется внутри Free) ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 21:20 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
BasketbolНо не могу понять как правильно реализовать мою задачу. Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude. Какая задача на самом деле? Вы сейчас описали не задачу, а реализацию... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 21.07.2019, 22:45 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
YuRockalekcvpBasketbol, Не говоря уже о том, что вы вообще не понимаете что вы делаете: Код: pascal 1. 2. 3. 4. 5. Не говоря о том, что Terminate и WaitFor будут вызваны в деструкторе (если он вызовется внутри Free) Что waitFor противоречит freeOnTerminate = true - я прекрасно знаю. И что данный форум не позволяет редактировать посты - тоже. FreeOnTerminate я делаю false при создании, поэтому все норм с этим. И что менять состояние vcl компонентов синхронайзом - я тоже знаю и делаю. Вопрос был именно про архитектуру. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 00:38 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
X-CiteBasketbolНо не могу понять как правильно реализовать мою задачу. Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude. Какая задача на самом деле? Вы сейчас описали не задачу, а реализацию... Есть некие последовательности действий: сделать то то, подождать выполнения какого то условия, сделать паузу столько то секунд и другие. Некоторые из этих действий затрагивают компоненты VCL. Я запускаю n потоков и для каждого потока я создаю n форм. Т.е. каждый поток работает со своей формой и не знает о существовании других потоков и форм. И на текущий момент нет никаких разделямых ресурсов. Соответственно мне не нужно делать никаких критических секций и семафоров. Но должна быть возможность закрытия форм пользователем в любой момент. В этом и была проблема. Соответственно, чтобы сделать это безопасно - я сначала должен дождаться полного уничтожения потока. В итоге к чему я пришел: 1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия. 2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия. 3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 05:23 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
[quot Basketbol]X-CiteВ итоге к чему я пришел: 1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия. 2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия. 3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь.В целом логика правильная. Как я понимаю реализация хромает и много повторяющего кода выходит? Можно и метод формы передать потоку на выполнение, вариантов много, вот пункт 3 уже и не такой обязательный выходит т.е. изначальная кривая архитектура RTL это не повод для уныния, напишите свою - дельфи пока ещё системный язык ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 07:53 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Недавно обсуждали нечто подобное: 21916011 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 08:03 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
BasketbolЯ запускаю n потоков и для каждого потока я создаю n форм. Т.е. каждый поток работает со своей формой и не знает о существовании других потоков и форм. Тогда какие проблемы? Описываешь экземпляр доп.потока в форме, которую будешь создавать. В потоке изменяешь gaude этой формы через synchronize/queue. Потом вызываешь эту форму столько раз, сколько нужно. И все. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 09:48 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
BasketbolВ итоге к чему я пришел: 1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия. 2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия. 3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь. Есть вероятность дедлока, когда форма из OnClose вызовет WaitFor потока, который в это время выполняет Synchronize с этой формой. В идеале от Synchronize надо полностью избавляться. Например, постить форме сообщения, а она уже в контексте главного потока будет что-то делать. Если без него ну совсем никак, то схема д.б. асинхронная: - Вызвали закрытие формы: -- проверить, не завершен ли поток, если да - то удалить его и закрыться -- если не закрыт: --- выставить флаг завершения (terminate) --- Запостить себе повторный WM_CLOSE -либо- ждать от потока сообщения "я завершился" -- на выход без закрытия ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 11:13 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Василий 2BasketbolВ итоге к чему я пришел: 1. Поток видит форму через свое поле. Поток должен знать о своей форме, ведь он с ней выполняет какие то действия. 2. Форма видит поток также через свое поле. Форма должна знать об управляющем потоке, ведь она должна его уничтожить во время своего закрытия. 3. Все действия с формой нужно реализовывать в классе потока. Во первых чтобы можно было использовать синхронайз, во вторых - чтобы постоянно анализировать terminate, дабы прекращать всяческие циклические операции когда форму закроет пользователь. Есть вероятность дедлока, когда форма из OnClose вызовет WaitFor потока, который в это время выполняет Synchronize с этой формой. В идеале от Synchronize надо полностью избавляться. Например, постить форме сообщения, а она уже в контексте главного потока будет что-то делать. Если без него ну совсем никак, то схема д.б. асинхронная: - Вызвали закрытие формы: -- проверить, не завершен ли поток, если да - то удалить его и закрыться -- если не закрыт: --- выставить флаг завершения (terminate) --- Запостить себе повторный WM_CLOSE -либо- ждать от потока сообщения "я завершился" -- на выход без закрытия Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 11:50 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
ziv-2014Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке. А. Ну да. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 11:59 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Василий 2ziv-2014Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке. А. Ну да. а если в Synchronize вызвать Application.PrcoessMessages? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 12:41 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
замечу, что кроме Synchronize существует Queue: http://docwiki.embarcadero.com/Libraries/XE5/en/System.Classes.TThread.Queue ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 12:43 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Есть такая офигенная библиотека GS.Bus - *InterThread* communication Application Bus for FPC/Delphi https://github.com/VincentGsell/GS.Core Библиотека для пользователя простая и надёжная, пользуюсь давно и без проблем Проблемы с синхронизациями куч потоков решаются целиком и полностью ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 13:05 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
ZeliusВасилий 2пропущено... А. Ну да. а если в Synchronize вызвать Application.PrcoessMessages? Какая разница - всеравно в основном потоке исполнится. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 13:38 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
BasketbolНо не могу понять как правильно реализовать мою задачу. Максимально упрощенная задача: Нужно выполнять параллельно несколько потоков, которые меняют свойство progress компонента-бегунка TGaude. Эту задачу правильно решить так. Каждый поток либо имеет собственные показатели прогресса (типа полей "сколько сделано" и "сколько всего надо") либо использует общие (например, когда одна задача делится на кучу исполняемых фрагментов). Доступ к показателям атомарный (например, через Interlocked-функции). На форме размещён таймер, который забирает эти данные, высчитывает и показывает прогресс. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 14:14 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
ziv-2014Не возможно вызвать одновременно WaitFor в OnClose и функцию из Synchronize - так что дедлоков тут не должно быть, т. к. эти функции исполняются в основном потоке.Ну почему же. Можно, например, внутри Synchronize вызвать Form1.Close; ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 14:14 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
ziv-2014Zeliusпропущено... а если в Synchronize вызвать Application.PrcoessMessages? Какая разница - всеравно в основном потоке исполнится. доп поток вызывает Syncrhonize, в котором вызывается Application.PrcoessMessages, в это время пользователь нажимает закрыть форму, у которой в OnClose стоит FThread.Free (Terminate+WaitFor+Destroy), а поток висит в TMonitor.Wait(SyncProcPtr.Signal, ThreadLock, INFINITE) - дедлок. Если поток уничтожать в OnDestroy, то дедлока не будет. Код: pascal 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58. 59. 60. 61. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 14:17 |
|
||
|
И опять про потоки и про формы
|
|||
|---|---|---|---|
|
#18+
Zeliusдоп поток вызывает Syncrhonize, в котором вызывается Application.PrcoessMessages, в это время пользователь нажимает закрыть форму, у которой в OnClose стоит FThread.Free Ну вот, еще как вариант. ZeliusЕсли поток уничтожать в OnDestroy, то дедлока не будет. Почему это. OnDestroy просто вызовется после OnClose, но это неважно, если это внутри Syncrhonize. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 22.07.2019, 14:51 |
|
||
|
|

start [/forum/topic.php?fid=58&msg=39839971&tid=2039232]: |
0ms |
get settings: |
11ms |
get forum list: |
22ms |
check forum access: |
6ms |
check topic access: |
6ms |
track hit: |
203ms |
get topic data: |
13ms |
get forum data: |
4ms |
get page messages: |
80ms |
get tp. blocked users: |
2ms |
| others: | 236ms |
| total: | 583ms |

| 0 / 0 |
