Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 2 582

/ вопрос открыт /

Здравствуйте, уважаемые эксперты!

Возникли проблемы по работе с потоками.

Проблема 1:
нужно, чтобы по истечению некоторого времени расчет (он реализован в TCalculatorThread.Execute) был завершен,
но расчет проходит полностью, и Event.WaitFor не отрабатывает,
что сделано не так
(код в Приложении к вопросу)


Проблема 2:

Запускаю тот же расчет кнопкой "Расчет", хочу, чтобы по нажатию кнопки "Прервать" расчет был убит, но не могу пока идет обработка метода нажатия кнопки "расчет" нажать кнопку "Прервать"

Подскажите, пожалуйста, как это можно сделать.

Заранее спасибо

Приложение:
  1. Event := TEvent.Create();
  2. Event.ResetEvent;
  3. FThread := TCalculatorThread.Create(Event, Self.FFormManager, FCallBack);
  4.  
  5. TimeOut := 5;
  6. FThread.WaitFor;
  7.  
  8.  
  9. then begin
  10. FThread.Terminate();
  11.  
  12. // Result := False;
  13. Exit;
  14. end;


Aндрей Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: Aндрей (статус: 1-ый класс)
Вопрос отправлен: 1 апреля 2009, 13:12
Состояние вопроса: открыт, ответов: 1.

Ответ #1. Отвечает эксперт: Вадим К

Здравствуйте, Aндрей!
Конечно Event.WaitFor не будет обрабатываться, потому что перед этим есть FThread.WaitFor, который дождется выполнения и завершения потока.
К тому же, крайне неверно в обработчике кнопки ждать завершения потока - вся прелесть работы с потоками теряется.
Я бы сделал так.
В самом коде потока, который занимается расчетами должна быть проверка поля terminated. и если оно истинно, то поток должен пойти на завершение (в самом простом случае - сохранить результаты и выйти с процедуры execute).
А выставляет это поле в true вызов метода FThread.Terminate();
То есть, если проверку поля не делать, то вызов FThread.Terminate(); не остановит поток. Вот так просто.
Думаю, что теперь понятно, как сделать кнопку "остановить расчет"? Рабочий поток должен время от времени проверять это поле, и решать что делать. Убить поток с другого потока напрямую - чревато различными проблемами. (это приблизительно равносильно, что у Вас есть Боинг и Вы хотите его остановить, пока он летит. Да, можно построить стену или сбить прямым ракетным попаданием, но могут быть такие разрушения... проще пилотам дать команду "остановитесь и садитесь".)
Как сделать таймаут, что бы прибивать расчет? есть три способа. Первый - поток вызывает функцию GetTickCount и смотрит, сколько он уже работает. Если время превышено - идет на завершение (есть функции, которые измеряют, сколько поток отработал времени. Но у них есть свои загвоздки). Сколько времени поток должен работать, можно передать при старте.
Второй способ - паралельно с запуском потока, запускаем таймер (TTimer или вызовом API функции SetTimer) и выставляем на заданное время. А в обработчике проверяем, работает ли наш поток, если нет - убиваем.
и третий способ, похожий на Ваш - поток запускаем через дополнительный поток, который его контролирует. Но здесь есть много чудных нюансов. Но если нужно контролировать много потоков, может быть хорошим. Если кол-во потоков несколько тысяч - уже могут быть проблемы.
И вопрос на последок - а как забрать результаты расчета с потока - наиболее красиво - в событии OnTerminate. Поток в этот момент уже отработал, но ещё не вызван деструктор. И, что не маловажно - эту функцию не нужно синхронизировать - она вызывается в контексте основного потока.

Ответ отправил: Вадим К (статус: Академик)
Время отправки: 1 апреля 2009, 13:41
Оценка за ответ: 5

Комментарий к оценке: спасибо за совет, буду пробывать

Мини-форум вопроса

Всего сообщений: 1; последнее сообщение — 20 апреля 2009, 09:35; участников в обсуждении: 1.
Aндрей

Aндрей (статус: 1-ый класс), 20 апреля 2009, 09:35 [#1]:

К сожалению, не могу справиться проблемой 2
Проблема 2:

Запускаю тот же расчет кнопкой "Расчет", хочу, чтобы по нажатию кнопки "Прервать" расчет был убит, но не могу пока идет обработка метода нажатия кнопки "расчет" нажать кнопку "Прервать"

Кнопка зажатой остается

------------------------------------
Что я делаю:

Запускаю поток, в котором запускаю метод Run(Self);
который по иерархии вызывает нужный метод Calculate()? в котором производится расчет, который может зависать

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 5 апреля 2020, 07:38
Выполнено за 0.02 сек.
Рейтинг@Mail.ru