Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.117.183.172] |
|
Страницы: (5) [1] 2 3 ... Последняя » все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Корректно ли делать вот так?
TThread.Synchronize(Th, Method); Именно поэтому я не стал писать: Th.Synchronize(Method) |
Сообщ.
#2
,
|
|
|
Задача какая стоит?
Указанная форма Synchronize - классовая статическая, применяется (пока) редко Nil использовать можно - главному потоку не всегда требуется знать, кто там синхронизируется. |
Сообщ.
#3
,
|
|
|
Не надо делать Synchronize, вот честно. Лучше делайте PostMessage и избавьтесь от привычки менять UI напрямую из рабочего потока. Ибо Synchronize - это не многопоточность, это ОДНОпоточность. Почитайте, как он работает - смысл тредов убивается напрочь, и владельцы многоядерников высылают автору программы заслуженные лучи поноса.
|
Сообщ.
#4
,
|
|
|
Ok, тогда ещё пара вопросов:
1. Как можно узнать, что TThread (с FreeOnTerminate = True) ещё работает, а не завершился? Если не вешаться на OnTerminate и устанавливать какую-нибудь переменную вне TThread. Вообще, можно ли определить, что объект освобождён? 2. И можно ли сделать так, чтобы переменная TThread обнулялась при завершении работы? Добавлено И правильно ли я понимаю, что если я прерву поток через TerminateThread (потому как метод Terminate ничего, по сути, не делает), то никакого Free не случится, т.к. этот самый Free (как и вызов метода Execute) происходит в том же самом потоке? Да и вообще, насколько это опасно: вызывать TerminateThread (ведь в ThreadProc много чего ещё происходит после Execute)? |
Сообщ.
#5
,
|
|
|
1. Посылать сообщение или выставлять событие. Собственно, OnTerminate решает эту задачу проще всего
>можно ли определить, что объект освобождён? Не нужно этого. 2. нет Спроектируй работу потоков корректно, тогда в абсолютном большинстве случаев не понадобится ничего обнулять и грубо останавливать поток. |
Сообщ.
#6
,
|
|
|
Цитата MBo @ Дело в том, что мне нужно остановить поток, в котором выполняется WinAPI-функция (в частности, MessageBox). Спроектируй работу потоков корректно, тогда в абсолютном большинстве случаев не понадобится ничего обнулять и грубо останавливать поток. |
Сообщ.
#7
,
|
|
|
В дополнительном потоке выполняется работа, требующая блокирующего обращения к пользовательскому интерфейсу??
Это неправильно. |
Сообщ.
#8
,
|
|
|
С чего вдруг это неправильно?
|
Сообщ.
#9
,
|
|
|
Цитата Jin X @ С чего вдруг это неправильно? Потому что потоку лучше делать расчёты "как заказано". Если у каждого потока будет свой UI, то взаимодействие между ними станет гораздо сложнее. Т.е. это по сути это будут Active Objects в стиле языка SmallTalk со товарищи (Хочешь что-то от потока? Положи ему в очередь сообщений команду. Когда именно он её обработает и ответит - предсказать нельзя, всё взаимодействие будет асинхронное в обе стороны. В результате, тривиальный код выливается в здоровенную state machine, которую трудно читать и ещё труднее - добавлять новый функционал. В ряде случаев синтаксис языка облегчает головную боль, типа кодогенераторов async-await в C# или асинхронных блоков в Objective-C, но кардинального облегчения не будет.) Поэтому в роли "заказчика" пусть выступает основной (aka визуальный) поток, и он уже будет подавать команды рабочему TThread, а тот в роли ведомого - репортить свои достижения обратно через PostMessage или ещё как (почитайте про shared memory, mutex, event и прочие механизмы синхронизации потоков). |
Сообщ.
#10
,
|
|
|
Цитата Jin X @ Да и вообще, насколько это опасно: вызывать TerminateThread (ведь в ThreadProc много чего ещё происходит после Execute)? Вызывать TerminateThread вообще опасно (см. ремарки мсдн), поэтому делать это рекомендуется только в исключительных случаях. После TerminateThread не только ThreadProc не выполняется, а вообще никакой user-mode code (а в XP и ниже даже стэк потока не очищается, что приводит к утечке памяти - по умолчанию 1 Мб адресного пространства). Соотв-но и состояния глобальных переменных, которые мог изменить поток, могут зависнуть в "неконсистентном состоянии". А это могут быть не только залоченные крит.секции, приводящие к очевидному дедлоку, но и неочевидные внутренние состояния системных библиотек, если прерывание потока происходит на вызове функции АПИ (о чем упоминается в тех же ремарках). Простейший пример: если ты собираешься убить поток во время показа MessageBox с hWnd <> 0, то после убийства окно hWnd так и останется заблокированным (disabled) и придется вызывать EnableWindow для его разблокировки. Вопрос - зачем это нужно, если можно решить эту проблему "мирными средствами" (например, вызвать Thread.Terminate и закрыть окно диалога). Цитата Jin X @ потому как метод Terminate ничего, по сути, не делает Этот метод делает то, что нужно - указывает потоку, что он должен сам завершиться, чтобы не пришлось прибегать к тяжелой артиллерии и ковровому бомбометанию в виде TerminateThread. Поэтому "корректно спроектированный поток", рассчитанный на длительную обработку (или возможные зависоны) должен периодически и\или в "узловых точках" (например, после показа диалога) проверять флаг Terminated и самостоятельно корректно завершаться при его установке. |
Сообщ.
#11
,
|
|
|
Цитата Jin X @ 1. Как можно узнать, что TThread (с FreeOnTerminate = True) ещё работает, а не завершился? Если не вешаться на OnTerminate и устанавливать какую-нибудь переменную вне TThread. Можно воспользоваться ReturnValue (менять значения придется самому) или Finished (ставится в True после завершения Execute, при повторном запуске не взводится). С FreeOnTerminate осторожней. Это хорошо для потоков "запустил и забыл", если программа гарантированно дождется завершения, но как только начинаешь рассчитывать на досрочное закрытие приложения, все резко становится намного веселее. |
Сообщ.
#12
,
|
|
|
Цитата Jin X @ Ok, тогда ещё пара вопросов: 1. ... 2. ... Если используешь FreeOnTerminate = True, то сохранять ссылку на TThread в переменной не имеет никакого смысла, т.к. при асинхронной работе объект может быть разрушен в любой момент, со всеми вытекающими отсюда прелестями, самой лучшей (но маловероятной) из которых является AV. И обнуление переменной тут ничего не даст, т.к. разрушение объекта может произойти сразу после проверки переменной на nil\Assigned. |
Сообщ.
#13
,
|
|
|
Цитата Mr.Delphist @ Зачем так заморачиваться?Если у каждого потока будет свой UI, то взаимодействие между ними станет гораздо сложнее.......... Речь идёт просто о единичном MessageBox в отдельном потоке, не более того Цитата leo @ Это да т.к. разрушение объекта может произойти сразу после проверки переменной на nil\Assigned В общем, решил TerminateThread заменить на EnumThreadWindows/SendMessage(WM_CLOSE) |
Сообщ.
#14
,
|
|
|
И все же такая архитектура глубоко порочна, кмк. Тут в рассылке ICS недавно один персонаж похожие штуки проворачивал - показывал мессаджбоксы из обработчиков асинхронных сокетов. Тоже знает толк в извращениях...
|
Сообщ.
#15
,
|
|
|
Fr0sT, в чём порочность? Конструктивно только, без пространных рассуждений о силах вселенной
Хорошо, пусть обычно основной поток используется для всяких GUI-штук, связки различных компонентов и основных действий. Дополнительные потоки - для вычислений и пр. сопутствующих радостей. Теперь ситуация: я хочу вывести MessageBox "в фоновом режиме" (немодальный то бишь - не будем тут поднимать вопрос "зачем"... если это кому-то непривычно, то не значит, что это не имеет права на жизнь), но такой "встроенной" возможности нет. Т.е. фактически это либо создание окна и работа с ним через VLC (или то же самое, но через WinAPI), либо вывод MessageBox/MessageBoxTimeout в отдельном потоке (ну не пихать же основной код программы в отдельный поток ради того, чтобы MessageBox выводился из основного - это явный бред). Вот здесь я об это уже писал: Найти и закрыть MessageBox Сейчас решил вернуться к этому и закончить дело. |