На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (5) [1] 2 3 ... Последняя » все  ( Перейти к последнему сообщению )  
> TThread.Synchronize
    Корректно ли делать вот так?
    ExpandedWrap disabled
      TThread.Synchronize(Th, Method);
    При том, что Th может быть = nil.
    Именно поэтому я не стал писать:
    ExpandedWrap disabled
      Th.Synchronize(Method)
      Задача какая стоит?
      Указанная форма Synchronize - классовая статическая, применяется (пока) редко

      Nil использовать можно - главному потоку не всегда требуется знать, кто там синхронизируется.
        Не надо делать Synchronize, вот честно. Лучше делайте PostMessage и избавьтесь от привычки менять UI напрямую из рабочего потока. Ибо Synchronize - это не многопоточность, это ОДНОпоточность. Почитайте, как он работает - смысл тредов убивается напрочь, и владельцы многоядерников высылают автору программы заслуженные лучи поноса.
          Ok, тогда ещё пара вопросов:

          1. Как можно узнать, что TThread (с FreeOnTerminate = True) ещё работает, а не завершился? Если не вешаться на OnTerminate и устанавливать какую-нибудь переменную вне TThread.
          Вообще, можно ли определить, что объект освобождён?

          2. И можно ли сделать так, чтобы переменная TThread обнулялась при завершении работы?

          Добавлено
          И правильно ли я понимаю, что если я прерву поток через TerminateThread (потому как метод Terminate ничего, по сути, не делает), то никакого Free не случится, т.к. этот самый Free (как и вызов метода Execute) происходит в том же самом потоке?
          Да и вообще, насколько это опасно: вызывать TerminateThread (ведь в ThreadProc много чего ещё происходит после Execute)?
            1. Посылать сообщение или выставлять событие. Собственно, OnTerminate решает эту задачу проще всего
            >можно ли определить, что объект освобождён?
            Не нужно этого.

            2. нет

            Спроектируй работу потоков корректно, тогда в абсолютном большинстве случаев не понадобится ничего обнулять и грубо останавливать поток.
              Цитата MBo @
              Спроектируй работу потоков корректно, тогда в абсолютном большинстве случаев не понадобится ничего обнулять и грубо останавливать поток.
              Дело в том, что мне нужно остановить поток, в котором выполняется WinAPI-функция (в частности, MessageBox).
                В дополнительном потоке выполняется работа, требующая блокирующего обращения к пользовательскому интерфейсу??
                Это неправильно.
                  С чего вдруг это неправильно?
                    Цитата Jin X @
                    С чего вдруг это неправильно?

                    Потому что потоку лучше делать расчёты "как заказано".

                    Если у каждого потока будет свой UI, то взаимодействие между ними станет гораздо сложнее. Т.е. это по сути это будут Active Objects в стиле языка SmallTalk со товарищи (Хочешь что-то от потока? Положи ему в очередь сообщений команду. Когда именно он её обработает и ответит - предсказать нельзя, всё взаимодействие будет асинхронное в обе стороны. В результате, тривиальный код выливается в здоровенную state machine, которую трудно читать и ещё труднее - добавлять новый функционал. В ряде случаев синтаксис языка облегчает головную боль, типа кодогенераторов async-await в C# или асинхронных блоков в Objective-C, но кардинального облегчения не будет.)

                    Поэтому в роли "заказчика" пусть выступает основной (aka визуальный) поток, и он уже будет подавать команды рабочему TThread, а тот в роли ведомого - репортить свои достижения обратно через PostMessage или ещё как (почитайте про shared memory, mutex, event и прочие механизмы синхронизации потоков).
                      Цитата 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 и самостоятельно корректно завершаться при его установке.
                      Сообщение отредактировано: leo -
                        Цитата Jin X @
                        1. Как можно узнать, что TThread (с FreeOnTerminate = True) ещё работает, а не завершился? Если не вешаться на OnTerminate и устанавливать какую-нибудь переменную вне TThread.

                        Можно воспользоваться ReturnValue (менять значения придется самому) или Finished (ставится в True после завершения Execute, при повторном запуске не взводится).
                        С FreeOnTerminate осторожней. Это хорошо для потоков "запустил и забыл", если программа гарантированно дождется завершения, но как только начинаешь рассчитывать на досрочное закрытие приложения, все резко становится намного веселее.
                        Сообщение отредактировано: Fr0sT -
                          Цитата Jin X @
                          Ok, тогда ещё пара вопросов:
                          1. ...
                          2. ...

                          Если используешь FreeOnTerminate = True, то сохранять ссылку на TThread в переменной не имеет никакого смысла, т.к. при асинхронной работе объект может быть разрушен в любой момент, со всеми вытекающими отсюда прелестями, самой лучшей (но маловероятной) из которых является AV. И обнуление переменной тут ничего не даст, т.к. разрушение объекта может произойти сразу после проверки переменной на nil\Assigned.
                          Сообщение отредактировано: leo -
                            Цитата Mr.Delphist @
                            Если у каждого потока будет свой UI, то взаимодействие между ними станет гораздо сложнее..........
                            Зачем так заморачиваться?
                            Речь идёт просто о единичном MessageBox в отдельном потоке, не более того

                            Цитата leo @
                            т.к. разрушение объекта может произойти сразу после проверки переменной на nil\Assigned
                            Это да :)

                            В общем, решил TerminateThread заменить на EnumThreadWindows/SendMessage(WM_CLOSE) :)
                              И все же такая архитектура глубоко порочна, кмк. Тут в рассылке ICS недавно один персонаж похожие штуки проворачивал - показывал мессаджбоксы из обработчиков асинхронных сокетов. Тоже знает толк в извращениях...
                                Fr0sT, в чём порочность? Конструктивно только, без пространных рассуждений о силах вселенной :)

                                Хорошо, пусть обычно основной поток используется для всяких GUI-штук, связки различных компонентов и основных действий. Дополнительные потоки - для вычислений и пр. сопутствующих радостей.
                                Теперь ситуация: я хочу вывести MessageBox "в фоновом режиме" (немодальный то бишь - не будем тут поднимать вопрос "зачем"... если это кому-то непривычно, то не значит, что это не имеет права на жизнь), но такой "встроенной" возможности нет. Т.е. фактически это либо создание окна и работа с ним через VLC (или то же самое, но через WinAPI), либо вывод MessageBox/MessageBoxTimeout в отдельном потоке (ну не пихать же основной код программы в отдельный поток ради того, чтобы MessageBox выводился из основного - это явный бред).

                                Вот здесь я об это уже писал: Найти и закрыть MessageBox
                                Сейчас решил вернуться к этому и закончить дело.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0466 ]   [ 16 queries used ]   [ Generated: 3.05.24, 04:09 GMT ]